@iamsergio/qttest-utils 2.5.0 → 2.6.0
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/CHANGELOG.md +13 -0
- package/out/cmake.d.ts +1 -0
- package/out/cmake.js +89 -19
- package/out/example.js +24 -10
- package/out/index.js +5 -1
- package/out/qttest.d.ts +2 -0
- package/out/qttest.js +51 -17
- package/out/test.js +38 -24
- package/out/utils.js +3 -1
- package/package.json +9 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.6.0](https://github.com/KDAB/qttest-utils/compare/v2.5.0...v2.6.0) (2026-04-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* propagate CTest ENVIRONMENT to spawned test processes ([ea24d96](https://github.com/KDAB/qttest-utils/commit/ea24d96545c3ac9d68fc9cfea8ab6b372055b804))
|
|
9
|
+
* propagate CTest ENVIRONMENT to spawned test processes ([6a68cc7](https://github.com/KDAB/qttest-utils/commit/6a68cc7db40f53f3631579477deb780d36b36685))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* made eslint pass ([6740d61](https://github.com/KDAB/qttest-utils/commit/6740d618843a9a0a55fd73b7cc9e0c9f2412788e))
|
|
15
|
+
|
|
3
16
|
## [2.5.0](https://github.com/KDAB/qttest-utils/compare/v2.4.4...v2.5.0) (2026-04-04)
|
|
4
17
|
|
|
5
18
|
|
package/out/cmake.d.ts
CHANGED
package/out/cmake.js
CHANGED
|
@@ -28,7 +28,7 @@ class CMakeTests {
|
|
|
28
28
|
*/
|
|
29
29
|
async tests() {
|
|
30
30
|
// TODO: Check if folder exists
|
|
31
|
-
if (this.buildDirPath.length
|
|
31
|
+
if (this.buildDirPath.length === 0) {
|
|
32
32
|
console.error("Could not find out cmake build dir");
|
|
33
33
|
return undefined;
|
|
34
34
|
}
|
|
@@ -43,7 +43,7 @@ class CMakeTests {
|
|
|
43
43
|
});
|
|
44
44
|
child.on("close", (code) => {
|
|
45
45
|
if (code === 0) {
|
|
46
|
-
if (output.length
|
|
46
|
+
if (output.length === 0) {
|
|
47
47
|
console.error("ctestJsonToList: Empty json output. Command was ctest --show-only=json-v1 , in " +
|
|
48
48
|
this.buildDirPath);
|
|
49
49
|
reject(new Error("Failed to get ctest JSON output"));
|
|
@@ -68,20 +68,76 @@ class CMakeTests {
|
|
|
68
68
|
let test = new CMakeTest();
|
|
69
69
|
test.command = testJSON.command;
|
|
70
70
|
test.cwd = testJSON.cwd;
|
|
71
|
+
// Extract environment information if present in ctest JSON.
|
|
72
|
+
// ctest may expose environment as `environment` (string or array),
|
|
73
|
+
// or embed it into `properties` either as an object or array.
|
|
74
|
+
try {
|
|
75
|
+
let envArr = undefined;
|
|
76
|
+
if (testJSON.environment) {
|
|
77
|
+
envArr = Array.isArray(testJSON.environment)
|
|
78
|
+
? testJSON.environment
|
|
79
|
+
: [testJSON.environment];
|
|
80
|
+
}
|
|
81
|
+
if (!envArr && testJSON.properties) {
|
|
82
|
+
const props = testJSON.properties;
|
|
83
|
+
// properties might be an object with ENVIRONMENT key or an array of {name,value} entries
|
|
84
|
+
if (!Array.isArray(props) && props.ENVIRONMENT) {
|
|
85
|
+
const val = props.ENVIRONMENT;
|
|
86
|
+
if (typeof val === "string") {
|
|
87
|
+
envArr = [val];
|
|
88
|
+
}
|
|
89
|
+
else if (Array.isArray(val)) {
|
|
90
|
+
envArr = val;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else if (Array.isArray(props)) {
|
|
94
|
+
for (const p of props) {
|
|
95
|
+
if (!p || !p.name) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (p.name === "ENVIRONMENT" || p.name === "Environment") {
|
|
99
|
+
const v = p.value;
|
|
100
|
+
if (typeof v === "string") {
|
|
101
|
+
envArr = [v];
|
|
102
|
+
}
|
|
103
|
+
else if (Array.isArray(v)) {
|
|
104
|
+
envArr = v;
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (envArr) {
|
|
112
|
+
test.environment = envArr;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
try {
|
|
117
|
+
(0, qttest_1.logMessage)("ctest: failed to parse environment for test: " +
|
|
118
|
+
JSON.stringify(testJSON) +
|
|
119
|
+
" error: " +
|
|
120
|
+
e);
|
|
121
|
+
}
|
|
122
|
+
catch (_) { }
|
|
123
|
+
}
|
|
71
124
|
return test;
|
|
72
125
|
});
|
|
73
126
|
// filter invalid tests:
|
|
74
127
|
tests = tests.filter((test) => {
|
|
75
128
|
// pretty print test
|
|
76
|
-
if (!test.command || test.command.length
|
|
129
|
+
if (!test.command || test.command.length === 0) {
|
|
77
130
|
return false;
|
|
131
|
+
}
|
|
78
132
|
let testExecutablePath = test.executablePath();
|
|
79
133
|
let baseName = path_1.default.basename(testExecutablePath).toLowerCase();
|
|
80
|
-
if (baseName.endsWith(".exe"))
|
|
134
|
+
if (baseName.endsWith(".exe")) {
|
|
81
135
|
baseName = baseName.substring(0, baseName.length - 4);
|
|
136
|
+
}
|
|
82
137
|
// People doing complicated things in add_test()
|
|
83
|
-
if (baseName
|
|
138
|
+
if (baseName === "ctest" || baseName === "cmake") {
|
|
84
139
|
return false;
|
|
140
|
+
}
|
|
85
141
|
return true;
|
|
86
142
|
});
|
|
87
143
|
return tests;
|
|
@@ -90,16 +146,19 @@ class CMakeTests {
|
|
|
90
146
|
/// codemodel should have a "projects" key at root.
|
|
91
147
|
targetNameForExecutable(executable, codemodel, workaround = false) {
|
|
92
148
|
let projects = codemodel["projects"];
|
|
93
|
-
if (!projects)
|
|
149
|
+
if (!projects) {
|
|
94
150
|
return undefined;
|
|
151
|
+
}
|
|
95
152
|
for (let project of projects) {
|
|
96
153
|
let targets = project["targets"];
|
|
97
|
-
if (!targets)
|
|
154
|
+
if (!targets) {
|
|
98
155
|
continue;
|
|
156
|
+
}
|
|
99
157
|
for (let target of targets) {
|
|
100
158
|
let artifacts = target["artifacts"];
|
|
101
|
-
if (!artifacts)
|
|
159
|
+
if (!artifacts) {
|
|
102
160
|
continue;
|
|
161
|
+
}
|
|
103
162
|
for (let artifact of artifacts) {
|
|
104
163
|
if (artifact.endsWith(".exe")) {
|
|
105
164
|
artifact = artifact.substring(0, artifact.length - 4);
|
|
@@ -120,18 +179,21 @@ class CMakeTests {
|
|
|
120
179
|
/// If workaround is true, then we workaround microsoft/vscode-cmake-tools-api/issues/7 where
|
|
121
180
|
/// the basename is correct but the path is bogus, and we only compare the basenames
|
|
122
181
|
filenamesAreEqual(file1, file2, workaround = false) {
|
|
123
|
-
if (file1.endsWith(".exe"))
|
|
182
|
+
if (file1.endsWith(".exe")) {
|
|
124
183
|
file1 = file1.substring(0, file1.length - 4);
|
|
125
|
-
|
|
184
|
+
}
|
|
185
|
+
if (file2.endsWith(".exe")) {
|
|
126
186
|
file2 = file2.substring(0, file2.length - 4);
|
|
187
|
+
}
|
|
127
188
|
file1 = file1.replace(/\\/g, "/");
|
|
128
189
|
file2 = file2.replace(/\\/g, "/");
|
|
129
190
|
if (process.platform === "win32") {
|
|
130
191
|
file1 = file1.toLowerCase();
|
|
131
192
|
file2 = file2.toLowerCase();
|
|
132
193
|
}
|
|
133
|
-
if (file1
|
|
194
|
+
if (file1 === file2) {
|
|
134
195
|
return true;
|
|
196
|
+
}
|
|
135
197
|
if (!workaround) {
|
|
136
198
|
// files aren't equal!
|
|
137
199
|
return false;
|
|
@@ -142,7 +204,7 @@ class CMakeTests {
|
|
|
142
204
|
return false;
|
|
143
205
|
}
|
|
144
206
|
/// Compare only basename, since path is bogus
|
|
145
|
-
return path_1.default.basename(file1, ".exe")
|
|
207
|
+
return path_1.default.basename(file1, ".exe") === path_1.default.basename(file2, ".exe");
|
|
146
208
|
}
|
|
147
209
|
/// Returns the list of .cpp files for the specified executable
|
|
148
210
|
/// codemodel is the CMake codemodel JSON object
|
|
@@ -150,20 +212,24 @@ class CMakeTests {
|
|
|
150
212
|
/// @param workaround If true, worksaround https://github.com/microsoft/vscode-cmake-tools-api/issues/7
|
|
151
213
|
cppFilesForExecutable(executable, codemodel, workaround = false) {
|
|
152
214
|
let projects = codemodel["projects"];
|
|
153
|
-
if (!projects)
|
|
215
|
+
if (!projects) {
|
|
154
216
|
return [];
|
|
217
|
+
}
|
|
155
218
|
for (let project of projects) {
|
|
156
219
|
let targets = project["targets"];
|
|
157
|
-
if (!targets)
|
|
220
|
+
if (!targets) {
|
|
158
221
|
continue;
|
|
222
|
+
}
|
|
159
223
|
for (let target of targets) {
|
|
160
224
|
let sourceDir = target["sourceDirectory"];
|
|
161
225
|
let artifacts = target["artifacts"];
|
|
162
|
-
if (!artifacts || !sourceDir)
|
|
226
|
+
if (!artifacts || !sourceDir) {
|
|
163
227
|
continue;
|
|
228
|
+
}
|
|
164
229
|
let targetType = target["type"];
|
|
165
|
-
if (targetType
|
|
230
|
+
if (targetType !== "EXECUTABLE") {
|
|
166
231
|
continue;
|
|
232
|
+
}
|
|
167
233
|
for (let artifact of artifacts) {
|
|
168
234
|
if (artifact.endsWith(".exe")) {
|
|
169
235
|
artifact = artifact.substring(0, artifact.length - 4);
|
|
@@ -172,14 +238,17 @@ class CMakeTests {
|
|
|
172
238
|
artifact = artifact.replace(/\\/g, "/");
|
|
173
239
|
if (this.filenamesAreEqual(executable, artifact, workaround)) {
|
|
174
240
|
let fileGroups = target["fileGroups"];
|
|
175
|
-
if (!fileGroups)
|
|
241
|
+
if (!fileGroups) {
|
|
176
242
|
continue;
|
|
243
|
+
}
|
|
177
244
|
for (let fileGroup of fileGroups) {
|
|
178
|
-
if (fileGroup["language"]
|
|
245
|
+
if (fileGroup["language"] !== "CXX" || fileGroup["isGenerated"]) {
|
|
179
246
|
continue;
|
|
247
|
+
}
|
|
180
248
|
let sources = fileGroup["sources"];
|
|
181
|
-
if (!sources)
|
|
249
|
+
if (!sources) {
|
|
182
250
|
continue;
|
|
251
|
+
}
|
|
183
252
|
let cppFiles = [];
|
|
184
253
|
for (let source of sources) {
|
|
185
254
|
if (!source.endsWith("mocs_compilation.cpp")) {
|
|
@@ -202,6 +271,7 @@ exports.CMakeTests = CMakeTests;
|
|
|
202
271
|
class CMakeTest {
|
|
203
272
|
command = [];
|
|
204
273
|
cwd = "";
|
|
274
|
+
environment = [];
|
|
205
275
|
id() {
|
|
206
276
|
return this.command.join(",");
|
|
207
277
|
}
|
package/out/example.js
CHANGED
|
@@ -10,13 +10,13 @@ const qttest_1 = require("./qttest");
|
|
|
10
10
|
const fs_1 = __importDefault(require("fs"));
|
|
11
11
|
async function example() {
|
|
12
12
|
const args = process.argv.slice(2);
|
|
13
|
-
if (args.length
|
|
13
|
+
if (args.length !== 1) {
|
|
14
14
|
console.error("ERROR: Expected a single argument with the build-dir with cmake tests!");
|
|
15
15
|
process.exit(2);
|
|
16
16
|
}
|
|
17
17
|
let buildDirPath = args[0];
|
|
18
18
|
if (!fs_1.default.existsSync(buildDirPath)) {
|
|
19
|
-
console.error(
|
|
19
|
+
console.error("Directory does not exist!");
|
|
20
20
|
process.exit(1);
|
|
21
21
|
}
|
|
22
22
|
let qt = new qttest_1.QtTests();
|
|
@@ -36,13 +36,23 @@ async function example() {
|
|
|
36
36
|
console.log("\nRunning tests...");
|
|
37
37
|
for (var executable of qt.qtTestExecutables) {
|
|
38
38
|
await executable.runTest();
|
|
39
|
-
if (executable.lastExitCode === 0)
|
|
39
|
+
if (executable.lastExitCode === 0) {
|
|
40
40
|
console.log(" PASS: " + executable.filename);
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
console.log(" FAIL: " +
|
|
44
|
+
executable.filename +
|
|
45
|
+
"; code=" +
|
|
46
|
+
executable.lastExitCode);
|
|
47
|
+
}
|
|
43
48
|
for (let slot of executable.slots) {
|
|
44
49
|
if (slot.lastTestFailure) {
|
|
45
|
-
console.log(" failed slot=" +
|
|
50
|
+
console.log(" failed slot=" +
|
|
51
|
+
slot.name +
|
|
52
|
+
"; path=" +
|
|
53
|
+
slot.lastTestFailure.filePath +
|
|
54
|
+
"; line=" +
|
|
55
|
+
slot.lastTestFailure.lineNumber);
|
|
46
56
|
}
|
|
47
57
|
else {
|
|
48
58
|
console.log(" pass: " + slot.name);
|
|
@@ -53,15 +63,19 @@ async function example() {
|
|
|
53
63
|
console.log("\nRunning single tests...");
|
|
54
64
|
let slot = qt.qtTestExecutables[1].slots[0];
|
|
55
65
|
await slot.runTest();
|
|
56
|
-
if (slot.lastTestFailure)
|
|
66
|
+
if (slot.lastTestFailure) {
|
|
57
67
|
console.log(" FAIL:" + JSON.stringify(slot.lastTestFailure));
|
|
58
|
-
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
59
70
|
console.log(" PASS:");
|
|
71
|
+
}
|
|
60
72
|
let slot2 = qt.qtTestExecutables[1].slots[2];
|
|
61
73
|
await slot2.runTest();
|
|
62
|
-
if (slot2.lastTestFailure)
|
|
74
|
+
if (slot2.lastTestFailure) {
|
|
63
75
|
console.log(" FAIL:" + JSON.stringify(slot2.lastTestFailure));
|
|
64
|
-
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
65
78
|
console.log(" PASS");
|
|
79
|
+
}
|
|
66
80
|
}
|
|
67
81
|
example();
|
package/out/index.js
CHANGED
|
@@ -6,6 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const cmake_1 = require("./cmake");
|
|
7
7
|
const qttest_1 = require("./qttest");
|
|
8
8
|
const qttest = {
|
|
9
|
-
QtTests: qttest_1.QtTests,
|
|
9
|
+
QtTests: qttest_1.QtTests,
|
|
10
|
+
QtTest: qttest_1.QtTest,
|
|
11
|
+
QtTestSlot: qttest_1.QtTestSlot,
|
|
12
|
+
CMakeTests: cmake_1.CMakeTests,
|
|
13
|
+
CMakeTest: cmake_1.CMakeTest,
|
|
10
14
|
};
|
|
11
15
|
exports.default = qttest;
|
package/out/qttest.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export declare class QtTest {
|
|
|
10
10
|
verbose: boolean;
|
|
11
11
|
vscodeTestItem: any | undefined;
|
|
12
12
|
slots: QtTestSlot[] | null;
|
|
13
|
+
environment: string[];
|
|
13
14
|
lastExitCode: number;
|
|
14
15
|
outputFunc: LoggerFunction | undefined;
|
|
15
16
|
constructor(filename: string, buildDirPath: string);
|
|
@@ -17,6 +18,7 @@ export declare class QtTest {
|
|
|
17
18
|
get label(): string;
|
|
18
19
|
relativeFilename(): string;
|
|
19
20
|
filenameWithoutExtension(): string;
|
|
21
|
+
private buildSpawnEnv;
|
|
20
22
|
/**
|
|
21
23
|
* Calls "./yourqttest -functions" and stores the results in the slots property.
|
|
22
24
|
*/
|
package/out/qttest.js
CHANGED
|
@@ -65,6 +65,8 @@ class QtTest {
|
|
|
65
65
|
vscodeTestItem;
|
|
66
66
|
/// The list of individual runnable test slots
|
|
67
67
|
slots = null;
|
|
68
|
+
/// Environment variables coming from CTest (array of "VAR=VALUE")
|
|
69
|
+
environment = [];
|
|
68
70
|
/// Set after running
|
|
69
71
|
lastExitCode = 0;
|
|
70
72
|
/// Allows the caller to receive the output of the test process
|
|
@@ -82,8 +84,9 @@ class QtTest {
|
|
|
82
84
|
relativeFilename() {
|
|
83
85
|
let result = path_1.default.relative(process.cwd(), this.filename);
|
|
84
86
|
// strip .exe, as we only use this for tests
|
|
85
|
-
if (result.endsWith(".exe"))
|
|
87
|
+
if (result.endsWith(".exe")) {
|
|
86
88
|
result = result.slice(0, -4);
|
|
89
|
+
}
|
|
87
90
|
// normalize slashes
|
|
88
91
|
result = result.replace(/\\/g, "/");
|
|
89
92
|
return result;
|
|
@@ -91,10 +94,23 @@ class QtTest {
|
|
|
91
94
|
/// returns filename without .exe extension
|
|
92
95
|
filenameWithoutExtension() {
|
|
93
96
|
let result = this.filename;
|
|
94
|
-
if (result.endsWith(".exe"))
|
|
97
|
+
if (result.endsWith(".exe")) {
|
|
95
98
|
result = result.slice(0, -4);
|
|
99
|
+
}
|
|
96
100
|
return result;
|
|
97
101
|
}
|
|
102
|
+
buildSpawnEnv() {
|
|
103
|
+
const env = Object.assign({}, process.env);
|
|
104
|
+
if (this.environment && Array.isArray(this.environment)) {
|
|
105
|
+
for (const kv of this.environment) {
|
|
106
|
+
const idx = kv.indexOf("=");
|
|
107
|
+
if (idx > -1) {
|
|
108
|
+
env[kv.substring(0, idx)] = kv.substring(idx + 1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return env;
|
|
113
|
+
}
|
|
98
114
|
/**
|
|
99
115
|
* Calls "./yourqttest -functions" and stores the results in the slots property.
|
|
100
116
|
*/
|
|
@@ -109,6 +125,7 @@ class QtTest {
|
|
|
109
125
|
}
|
|
110
126
|
const child = (0, child_process_1.spawn)(this.filename, ["-functions"], {
|
|
111
127
|
cwd: this.buildDirPath,
|
|
128
|
+
env: this.buildSpawnEnv(),
|
|
112
129
|
});
|
|
113
130
|
child.stdout.on("data", (chunk) => {
|
|
114
131
|
output += chunk.toString();
|
|
@@ -154,8 +171,9 @@ class QtTest {
|
|
|
154
171
|
return undefined;
|
|
155
172
|
}
|
|
156
173
|
return new Promise((resolve, reject) => {
|
|
157
|
-
if (this.verbose)
|
|
174
|
+
if (this.verbose) {
|
|
158
175
|
logMessage("qttest: Running ldd on " + this.filename);
|
|
176
|
+
}
|
|
159
177
|
const child = (0, child_process_1.spawn)("ldd", [this.filename]);
|
|
160
178
|
let output = "";
|
|
161
179
|
let result = false;
|
|
@@ -166,8 +184,9 @@ class QtTest {
|
|
|
166
184
|
result = true;
|
|
167
185
|
}
|
|
168
186
|
}
|
|
169
|
-
if (this.verbose)
|
|
187
|
+
if (this.verbose) {
|
|
170
188
|
logMessage(chunk.toString());
|
|
189
|
+
}
|
|
171
190
|
});
|
|
172
191
|
child.on("exit", (code) => {
|
|
173
192
|
if (code === 0) {
|
|
@@ -183,7 +202,9 @@ class QtTest {
|
|
|
183
202
|
/// Note that if this is not a QtTest it might not run help and instead execute the test itself
|
|
184
203
|
async isQtTestViaHelp() {
|
|
185
204
|
return await new Promise((resolve, reject) => {
|
|
186
|
-
const child = (0, child_process_1.spawn)(this.filename, ["-help"]
|
|
205
|
+
const child = (0, child_process_1.spawn)(this.filename, ["-help"], {
|
|
206
|
+
env: this.buildSpawnEnv(),
|
|
207
|
+
});
|
|
187
208
|
let output = "";
|
|
188
209
|
let result = false;
|
|
189
210
|
child.stdout.on("data", (chunk) => {
|
|
@@ -204,11 +225,13 @@ class QtTest {
|
|
|
204
225
|
});
|
|
205
226
|
}
|
|
206
227
|
slotByName(name) {
|
|
207
|
-
if (!this.slots)
|
|
228
|
+
if (!this.slots) {
|
|
208
229
|
return undefined;
|
|
230
|
+
}
|
|
209
231
|
for (let slot of this.slots) {
|
|
210
|
-
if (slot.name
|
|
232
|
+
if (slot.name === name) {
|
|
211
233
|
return slot;
|
|
234
|
+
}
|
|
212
235
|
}
|
|
213
236
|
return undefined;
|
|
214
237
|
}
|
|
@@ -234,22 +257,28 @@ class QtTest {
|
|
|
234
257
|
args.join(" ") +
|
|
235
258
|
" with cwd=" +
|
|
236
259
|
cwdDir);
|
|
237
|
-
const child = (0, child_process_1.spawn)(this.filename, args, {
|
|
260
|
+
const child = (0, child_process_1.spawn)(this.filename, args, {
|
|
261
|
+
cwd: cwdDir,
|
|
262
|
+
env: this.buildSpawnEnv(),
|
|
263
|
+
});
|
|
238
264
|
if (this.outputFunc) {
|
|
239
265
|
// Callers wants the process output:
|
|
240
266
|
child.stdout.on("data", (chunk) => {
|
|
241
|
-
if (this.outputFunc)
|
|
267
|
+
if (this.outputFunc) {
|
|
242
268
|
this.outputFunc(chunk.toString());
|
|
269
|
+
}
|
|
243
270
|
});
|
|
244
271
|
child.stderr.on("data", (chunk) => {
|
|
245
|
-
if (this.outputFunc)
|
|
272
|
+
if (this.outputFunc) {
|
|
246
273
|
this.outputFunc(chunk.toString());
|
|
274
|
+
}
|
|
247
275
|
});
|
|
248
276
|
}
|
|
249
277
|
child.on("exit", async (code) => {
|
|
250
278
|
/// Can code even be null ?
|
|
251
|
-
if (code
|
|
279
|
+
if (code === undefined || code === null) {
|
|
252
280
|
code = -1;
|
|
281
|
+
}
|
|
253
282
|
if (!slot) {
|
|
254
283
|
this.lastExitCode = code;
|
|
255
284
|
}
|
|
@@ -303,13 +332,15 @@ class QtTest {
|
|
|
303
332
|
else {
|
|
304
333
|
let failedResults = [];
|
|
305
334
|
try {
|
|
306
|
-
const
|
|
307
|
-
for (let event of
|
|
335
|
+
const tapEvents = tap_parser_1.Parser.parse(data);
|
|
336
|
+
for (let event of tapEvents) {
|
|
308
337
|
try {
|
|
309
|
-
if (event.length < 2)
|
|
338
|
+
if (event.length < 2) {
|
|
310
339
|
continue;
|
|
311
|
-
|
|
340
|
+
}
|
|
341
|
+
if (event.at(0) !== "assert") {
|
|
312
342
|
continue;
|
|
343
|
+
}
|
|
313
344
|
var obj = event.at(1);
|
|
314
345
|
let pass = obj["ok"] === true;
|
|
315
346
|
let xfail = !pass && obj["todo"] !== false;
|
|
@@ -348,7 +379,7 @@ class QtTest {
|
|
|
348
379
|
});
|
|
349
380
|
});
|
|
350
381
|
for (let failure of failures) {
|
|
351
|
-
if (slot && slot.name
|
|
382
|
+
if (slot && slot.name !== failure.name) {
|
|
352
383
|
// We executed a single slot, ignore anything else
|
|
353
384
|
continue;
|
|
354
385
|
}
|
|
@@ -407,6 +438,8 @@ class QtTests {
|
|
|
407
438
|
if (ctests) {
|
|
408
439
|
for (let ctest of ctests) {
|
|
409
440
|
let qtest = new QtTest(ctest.executablePath(), buildDirPath);
|
|
441
|
+
// Propagate environment from CTest metadata
|
|
442
|
+
qtest.environment = ctest.environment;
|
|
410
443
|
this.qtTestExecutables.push(qtest);
|
|
411
444
|
}
|
|
412
445
|
}
|
|
@@ -453,8 +486,9 @@ class QtTests {
|
|
|
453
486
|
}
|
|
454
487
|
async dumpTestSlots() {
|
|
455
488
|
for (var ex of this.qtTestExecutables) {
|
|
456
|
-
if (!ex.slots)
|
|
489
|
+
if (!ex.slots) {
|
|
457
490
|
await ex.parseAvailableSlots();
|
|
491
|
+
}
|
|
458
492
|
console.log(ex.filename);
|
|
459
493
|
if (ex.slots) {
|
|
460
494
|
for (let slot of ex.slots) {
|
package/out/test.js
CHANGED
|
@@ -10,14 +10,28 @@ const qttest_1 = require("./qttest");
|
|
|
10
10
|
async function runTests(buildDirPath) {
|
|
11
11
|
let qt = new qttest_1.QtTests();
|
|
12
12
|
await qt.discoverViaCMake(buildDirPath);
|
|
13
|
-
|
|
13
|
+
// Verify that environment properties from CTest were discovered for test1
|
|
14
|
+
const test1Exe = qt.qtTestExecutables.find((e) => e.filenameWithoutExtension().endsWith("test1"));
|
|
15
|
+
if (!test1Exe) {
|
|
16
|
+
console.error("Expected to find test1 executable after discovery");
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
if (!test1Exe.environment || !test1Exe.environment.includes("MY_ENV=VALUE")) {
|
|
20
|
+
console.error("Expected test1 to have environment MY_ENV=VALUE, got: " +
|
|
21
|
+
JSON.stringify(test1Exe.environment));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
let expectedExecutables = [
|
|
14
25
|
"test/qt_test/build-dev/test1",
|
|
15
26
|
"test/qt_test/build-dev/test2",
|
|
16
27
|
"test/qt_test/build-dev/test3",
|
|
17
28
|
"test/qt_test/build-dev/non_qttest",
|
|
18
29
|
];
|
|
19
|
-
if (qt.qtTestExecutables.length
|
|
20
|
-
console.error("Expected
|
|
30
|
+
if (qt.qtTestExecutables.length !== expectedExecutables.length) {
|
|
31
|
+
console.error("Expected " +
|
|
32
|
+
expectedExecutables.length +
|
|
33
|
+
" executables, got " +
|
|
34
|
+
qt.qtTestExecutables.length);
|
|
21
35
|
process.exit(1);
|
|
22
36
|
}
|
|
23
37
|
await qt.removeNonLinking();
|
|
@@ -26,7 +40,7 @@ async function runTests(buildDirPath) {
|
|
|
26
40
|
await qt.removeByRunningHelp();
|
|
27
41
|
/// Remove the non-qttest executable from qt.qtTestExecutables
|
|
28
42
|
qt.qtTestExecutables = qt.qtTestExecutables.filter((e) => !e.filenameWithoutExtension().endsWith("non_qttest"));
|
|
29
|
-
if (qt.qtTestExecutables.length
|
|
43
|
+
if (qt.qtTestExecutables.length !== 3) {
|
|
30
44
|
console.error("Expected 3 executables, at this point got " +
|
|
31
45
|
qt.qtTestExecutables.length);
|
|
32
46
|
process.exit(1);
|
|
@@ -34,8 +48,8 @@ async function runTests(buildDirPath) {
|
|
|
34
48
|
// 1. Test that the executable test names are correct:
|
|
35
49
|
var i = 0;
|
|
36
50
|
for (var executable of qt.qtTestExecutables) {
|
|
37
|
-
let expected =
|
|
38
|
-
if (executable.relativeFilename()
|
|
51
|
+
let expected = expectedExecutables[i];
|
|
52
|
+
if (executable.relativeFilename() !== expected) {
|
|
39
53
|
console.error("Expected executable " +
|
|
40
54
|
expected +
|
|
41
55
|
", got " +
|
|
@@ -46,7 +60,7 @@ async function runTests(buildDirPath) {
|
|
|
46
60
|
}
|
|
47
61
|
// 2. Test that the discovered slots are correct:
|
|
48
62
|
await qt.dumpTestSlots();
|
|
49
|
-
let
|
|
63
|
+
let expectedSlots = {
|
|
50
64
|
"test/qt_test/build-dev/test1": ["testA", "testB", "testC", "testXFAIL"],
|
|
51
65
|
"test/qt_test/build-dev/test2": [
|
|
52
66
|
"testD",
|
|
@@ -60,25 +74,25 @@ async function runTests(buildDirPath) {
|
|
|
60
74
|
for (var executable of qt.qtTestExecutables) {
|
|
61
75
|
var i = 0;
|
|
62
76
|
for (let slot of executable.slots) {
|
|
63
|
-
let
|
|
64
|
-
if (slot.name
|
|
65
|
-
console.error("Expected slot " +
|
|
77
|
+
let expectedSlot = expectedSlots[executable.relativeFilename()][i];
|
|
78
|
+
if (slot.name !== expectedSlot) {
|
|
79
|
+
console.error("Expected slot " + expectedSlot + ", got " + slot.name);
|
|
66
80
|
process.exit(1);
|
|
67
81
|
}
|
|
68
82
|
i++;
|
|
69
83
|
}
|
|
70
84
|
}
|
|
71
85
|
// 3. Run the tests:
|
|
72
|
-
let
|
|
86
|
+
let expectedSuccess = [true, false, false];
|
|
73
87
|
var i = 0;
|
|
74
88
|
for (var executable of qt.qtTestExecutables) {
|
|
75
89
|
await executable.runTest();
|
|
76
90
|
let wasSuccess = executable.lastExitCode === 0;
|
|
77
|
-
if (wasSuccess && !
|
|
91
|
+
if (wasSuccess && !expectedSuccess[i]) {
|
|
78
92
|
console.error("Expected test to fail: " + executable.filename);
|
|
79
93
|
process.exit(1);
|
|
80
94
|
}
|
|
81
|
-
else if (!wasSuccess &&
|
|
95
|
+
else if (!wasSuccess && expectedSuccess[i]) {
|
|
82
96
|
console.error("Expected test to pass: " + executable.filename);
|
|
83
97
|
process.exit(1);
|
|
84
98
|
}
|
|
@@ -105,7 +119,7 @@ async function runTests(buildDirPath) {
|
|
|
105
119
|
}
|
|
106
120
|
// 5. Test executablesContainingSlot
|
|
107
121
|
let executables = qt.executablesContainingSlot("testB");
|
|
108
|
-
if (executables.length
|
|
122
|
+
if (executables.length !== 1) {
|
|
109
123
|
console.error("Expected 1 executable, got " + executables.length);
|
|
110
124
|
process.exit(1);
|
|
111
125
|
}
|
|
@@ -114,13 +128,13 @@ async function runTests(buildDirPath) {
|
|
|
114
128
|
process.exit(1);
|
|
115
129
|
}
|
|
116
130
|
executables = qt.executablesContainingSlot("non_existing");
|
|
117
|
-
if (executables.length
|
|
131
|
+
if (executables.length !== 0) {
|
|
118
132
|
console.error("Expected 0 executables, got " + executables.length);
|
|
119
133
|
process.exit(1);
|
|
120
134
|
}
|
|
121
135
|
// 6. Run a slot that has XFAIL
|
|
122
136
|
slot = qt.qtTestExecutables[0].slots[3];
|
|
123
|
-
if (slot.name
|
|
137
|
+
if (slot.name !== "testXFAIL") {
|
|
124
138
|
console.error("Expected slot name to be testXFAIL");
|
|
125
139
|
process.exit(1);
|
|
126
140
|
}
|
|
@@ -131,7 +145,7 @@ async function runTests(buildDirPath) {
|
|
|
131
145
|
}
|
|
132
146
|
// 7. Run a slot that has XPASS
|
|
133
147
|
slot = qt.qtTestExecutables[1].slots[3];
|
|
134
|
-
if (slot.name
|
|
148
|
+
if (slot.name !== "testXPASS") {
|
|
135
149
|
console.error("Expected slot name to be testXPASS");
|
|
136
150
|
process.exit(1);
|
|
137
151
|
}
|
|
@@ -142,7 +156,7 @@ async function runTests(buildDirPath) {
|
|
|
142
156
|
}
|
|
143
157
|
// 8. Run a slot that has both XFAIL and FAIL
|
|
144
158
|
slot = qt.qtTestExecutables[1].slots[4];
|
|
145
|
-
if (slot.name
|
|
159
|
+
if (slot.name !== "testMixXFAILWithFAIL") {
|
|
146
160
|
console.error("Expected slot name to be testMixXFAILWithFAIL");
|
|
147
161
|
process.exit(1);
|
|
148
162
|
}
|
|
@@ -158,29 +172,29 @@ async function runCodeModelTests(codeModelFile) {
|
|
|
158
172
|
let codemodelJson = JSON.parse(codemodelStr);
|
|
159
173
|
let cmake = new cmake_1.CMakeTests("random");
|
|
160
174
|
let files = cmake.cppFilesForExecutable("/vscode-qttest/test/qt_test/build-dev/test1", codemodelJson);
|
|
161
|
-
if (files.length
|
|
175
|
+
if (files.length !== 1) {
|
|
162
176
|
console.error("Expected 1 file, got " + files.length);
|
|
163
177
|
process.exit(1);
|
|
164
178
|
}
|
|
165
179
|
let expected = "/vscode-qttest/test/qt_test/test1.cpp";
|
|
166
180
|
let got = files[0].replace(/\\/g, "/");
|
|
167
|
-
if (got
|
|
181
|
+
if (got !== expected) {
|
|
168
182
|
console.error("Expected " + expected + ", got " + got);
|
|
169
183
|
process.exit(1);
|
|
170
184
|
}
|
|
171
185
|
let targetName = cmake.targetNameForExecutable("/vscode-qttest/test/qt_test/build-dev/test1", codemodelJson);
|
|
172
|
-
if (targetName
|
|
186
|
+
if (targetName !== "test1") {
|
|
173
187
|
console.error("Expected test1, got " + targetName);
|
|
174
188
|
process.exit(1);
|
|
175
189
|
}
|
|
176
190
|
// test windows back slashes:
|
|
177
191
|
files = cmake.cppFilesForExecutable("/vscode-qttest/test/qt_test/build-dev/test2", codemodelJson);
|
|
178
|
-
if (files.length
|
|
192
|
+
if (files.length !== 1) {
|
|
179
193
|
console.error("Expected 1 file, got " + files.length);
|
|
180
194
|
process.exit(1);
|
|
181
195
|
}
|
|
182
196
|
targetName = cmake.targetNameForExecutable("/vscode-qttest/test/qt_test/build-dev/test2", codemodelJson);
|
|
183
|
-
if (targetName
|
|
197
|
+
if (targetName !== "test2") {
|
|
184
198
|
console.error("Expected test2, got " + targetName);
|
|
185
199
|
process.exit(1);
|
|
186
200
|
}
|
|
@@ -205,7 +219,7 @@ async function runCodeModelTests(codeModelFile) {
|
|
|
205
219
|
}
|
|
206
220
|
targetName = cmake.targetNameForExecutable("/vscode-qttest/test/qt_test/build-dev/test3", codemodelJson,
|
|
207
221
|
/*workaround=*/ true);
|
|
208
|
-
if (targetName
|
|
222
|
+
if (targetName !== "test3") {
|
|
209
223
|
console.error("Expected null, got " + targetName);
|
|
210
224
|
process.exit(1);
|
|
211
225
|
}
|
package/out/utils.js
CHANGED
|
@@ -87,7 +87,9 @@ function executableFiles(folderPath) {
|
|
|
87
87
|
if (info.isDirectory()) {
|
|
88
88
|
executables = executables.concat(executableFiles(childPath));
|
|
89
89
|
}
|
|
90
|
-
else if (info.isFile() &&
|
|
90
|
+
else if (info.isFile() &&
|
|
91
|
+
!isLibrary(path_1.default.basename(childPath)) &&
|
|
92
|
+
isExecutable(childPath)) {
|
|
91
93
|
executables.push(childPath);
|
|
92
94
|
}
|
|
93
95
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iamsergio/qttest-utils",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
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",
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
11
|
-
"prepublishOnly": "npm run build"
|
|
11
|
+
"prepublishOnly": "npm run build",
|
|
12
|
+
"format:check": "prettier --check \"src/**/*.ts\"",
|
|
13
|
+
"format:fix": "prettier --write \"src/**/*.ts\""
|
|
12
14
|
},
|
|
13
15
|
"main": "out/index.js",
|
|
14
16
|
"typings": "./out/index.d.ts",
|
|
@@ -30,10 +32,13 @@
|
|
|
30
32
|
},
|
|
31
33
|
"devDependencies": {
|
|
32
34
|
"@types/node": "^22.0.0",
|
|
35
|
+
"eslint": "^9.0.0",
|
|
36
|
+
"prettier": "3.8.1",
|
|
33
37
|
"ts-node": "^10.9.2",
|
|
34
|
-
"typescript": "^
|
|
38
|
+
"typescript": "^6.0.2",
|
|
39
|
+
"typescript-eslint": "^8.0.0"
|
|
35
40
|
},
|
|
36
41
|
"dependencies": {
|
|
37
|
-
"tap-parser": "^
|
|
42
|
+
"tap-parser": "^18.3.0"
|
|
38
43
|
}
|
|
39
44
|
}
|