@iamsergio/qttest-utils 2.5.0 → 2.6.1

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 CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.6.1](https://github.com/KDAB/qttest-utils/compare/v2.6.0...v2.6.1) (2026-04-05)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * Improve gtest vs qttest detection ([75b2f57](https://github.com/KDAB/qttest-utils/commit/75b2f575962edc2e78737dc8615c5476bd62e8b2))
9
+ * Improve gtest vs qttest detection ([cb26f31](https://github.com/KDAB/qttest-utils/commit/cb26f316de3e882802e2c81df9c517e6658f9821))
10
+
11
+ ## [2.6.0](https://github.com/KDAB/qttest-utils/compare/v2.5.0...v2.6.0) (2026-04-05)
12
+
13
+
14
+ ### Features
15
+
16
+ * propagate CTest ENVIRONMENT to spawned test processes ([ea24d96](https://github.com/KDAB/qttest-utils/commit/ea24d96545c3ac9d68fc9cfea8ab6b372055b804))
17
+ * propagate CTest ENVIRONMENT to spawned test processes ([6a68cc7](https://github.com/KDAB/qttest-utils/commit/6a68cc7db40f53f3631579477deb780d36b36685))
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * made eslint pass ([6740d61](https://github.com/KDAB/qttest-utils/commit/6740d618843a9a0a55fd73b7cc9e0c9f2412788e))
23
+
3
24
  ## [2.5.0](https://github.com/KDAB/qttest-utils/compare/v2.4.4...v2.5.0) (2026-04-04)
4
25
 
5
26
 
package/out/cmake.d.ts CHANGED
@@ -20,6 +20,7 @@ export declare class CMakeTests {
20
20
  export declare class CMakeTest {
21
21
  command: string[];
22
22
  cwd: string;
23
+ environment: string[];
23
24
  id(): string;
24
25
  label(): string;
25
26
  executablePath(): string;
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 == 0) {
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 == 0) {
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 == 0)
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 == "ctest" || baseName === "cmake")
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
- if (file2.endsWith(".exe"))
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 == file2)
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") == path_1.default.basename(file2, ".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 != "EXECUTABLE")
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"] != "CXX" || fileGroup["isGenerated"])
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 != 1) {
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('Directory does not exist!');
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
- else
42
- console.log(" FAIL: " + executable.filename + "; code=" + executable.lastExitCode);
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=" + slot.name + "; path=" + slot.lastTestFailure.filePath + "; line=" + slot.lastTestFailure.lineNumber);
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
- else
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
- else
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, QtTest: qttest_1.QtTest, QtTestSlot: qttest_1.QtTestSlot, CMakeTests: cmake_1.CMakeTests, CMakeTest: cmake_1.CMakeTest
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
  */
@@ -30,6 +32,7 @@ export declare class QtTest {
30
32
  */
31
33
  linksToQtTestLib(): Promise<boolean> | undefined;
32
34
  isQtTestViaHelp(): Promise<boolean | undefined>;
35
+ isGTest(): Promise<boolean>;
33
36
  slotByName(name: string): QtTestSlot | undefined;
34
37
  runTest(slot?: QtTestSlot, cwd?: string): Promise<boolean>;
35
38
  tapOutputFileName(slot?: QtTestSlot): string;
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,14 +94,32 @@ 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
  */
101
117
  async parseAvailableSlots() {
118
+ if (await this.isGTest()) {
119
+ logMessage("qttest: Skipping -functions for GTest executable: " + this.filename);
120
+ this.slots = [];
121
+ return;
122
+ }
102
123
  let slotNames = [];
103
124
  let output = "";
104
125
  let err = "";
@@ -109,6 +130,7 @@ class QtTest {
109
130
  }
110
131
  const child = (0, child_process_1.spawn)(this.filename, ["-functions"], {
111
132
  cwd: this.buildDirPath,
133
+ env: this.buildSpawnEnv(),
112
134
  });
113
135
  child.stdout.on("data", (chunk) => {
114
136
  output += chunk.toString();
@@ -154,8 +176,9 @@ class QtTest {
154
176
  return undefined;
155
177
  }
156
178
  return new Promise((resolve, reject) => {
157
- if (this.verbose)
179
+ if (this.verbose) {
158
180
  logMessage("qttest: Running ldd on " + this.filename);
181
+ }
159
182
  const child = (0, child_process_1.spawn)("ldd", [this.filename]);
160
183
  let output = "";
161
184
  let result = false;
@@ -166,8 +189,9 @@ class QtTest {
166
189
  result = true;
167
190
  }
168
191
  }
169
- if (this.verbose)
192
+ if (this.verbose) {
170
193
  logMessage(chunk.toString());
194
+ }
171
195
  });
172
196
  child.on("exit", (code) => {
173
197
  if (code === 0) {
@@ -183,7 +207,9 @@ class QtTest {
183
207
  /// Note that if this is not a QtTest it might not run help and instead execute the test itself
184
208
  async isQtTestViaHelp() {
185
209
  return await new Promise((resolve, reject) => {
186
- const child = (0, child_process_1.spawn)(this.filename, ["-help"]);
210
+ const child = (0, child_process_1.spawn)(this.filename, ["-help"], {
211
+ env: this.buildSpawnEnv(),
212
+ });
187
213
  let output = "";
188
214
  let result = false;
189
215
  child.stdout.on("data", (chunk) => {
@@ -203,12 +229,41 @@ class QtTest {
203
229
  });
204
230
  });
205
231
  }
232
+ /// Returns whether this executable is a Google Test by running it with --help
233
+ /// and checking if the output contains the GTest banner
234
+ async isGTest() {
235
+ return await new Promise((resolve) => {
236
+ if (!fs.existsSync(this.filename)) {
237
+ resolve(false);
238
+ return;
239
+ }
240
+ const child = (0, child_process_1.spawn)(this.filename, ["--help"], {
241
+ env: this.buildSpawnEnv(),
242
+ });
243
+ let output = "";
244
+ let found = false;
245
+ child.stdout.on("data", (chunk) => {
246
+ if (!found) {
247
+ if (chunk
248
+ .toString()
249
+ .includes("This program contains tests written using Google Test")) {
250
+ found = true;
251
+ }
252
+ }
253
+ });
254
+ child.on("exit", () => {
255
+ resolve(found);
256
+ });
257
+ });
258
+ }
206
259
  slotByName(name) {
207
- if (!this.slots)
260
+ if (!this.slots) {
208
261
  return undefined;
262
+ }
209
263
  for (let slot of this.slots) {
210
- if (slot.name == name)
264
+ if (slot.name === name) {
211
265
  return slot;
266
+ }
212
267
  }
213
268
  return undefined;
214
269
  }
@@ -234,22 +289,28 @@ class QtTest {
234
289
  args.join(" ") +
235
290
  " with cwd=" +
236
291
  cwdDir);
237
- const child = (0, child_process_1.spawn)(this.filename, args, { cwd: cwdDir });
292
+ const child = (0, child_process_1.spawn)(this.filename, args, {
293
+ cwd: cwdDir,
294
+ env: this.buildSpawnEnv(),
295
+ });
238
296
  if (this.outputFunc) {
239
297
  // Callers wants the process output:
240
298
  child.stdout.on("data", (chunk) => {
241
- if (this.outputFunc)
299
+ if (this.outputFunc) {
242
300
  this.outputFunc(chunk.toString());
301
+ }
243
302
  });
244
303
  child.stderr.on("data", (chunk) => {
245
- if (this.outputFunc)
304
+ if (this.outputFunc) {
246
305
  this.outputFunc(chunk.toString());
306
+ }
247
307
  });
248
308
  }
249
309
  child.on("exit", async (code) => {
250
310
  /// Can code even be null ?
251
- if (code == undefined)
311
+ if (code === undefined || code === null) {
252
312
  code = -1;
313
+ }
253
314
  if (!slot) {
254
315
  this.lastExitCode = code;
255
316
  }
@@ -303,13 +364,15 @@ class QtTest {
303
364
  else {
304
365
  let failedResults = [];
305
366
  try {
306
- const tap_events = tap_parser_1.Parser.parse(data);
307
- for (let event of tap_events) {
367
+ const tapEvents = tap_parser_1.Parser.parse(data);
368
+ for (let event of tapEvents) {
308
369
  try {
309
- if (event.length < 2)
370
+ if (event.length < 2) {
310
371
  continue;
311
- if (event.at(0) != "assert")
372
+ }
373
+ if (event.at(0) !== "assert") {
312
374
  continue;
375
+ }
313
376
  var obj = event.at(1);
314
377
  let pass = obj["ok"] === true;
315
378
  let xfail = !pass && obj["todo"] !== false;
@@ -348,7 +411,7 @@ class QtTest {
348
411
  });
349
412
  });
350
413
  for (let failure of failures) {
351
- if (slot && slot.name != failure.name) {
414
+ if (slot && slot.name !== failure.name) {
352
415
  // We executed a single slot, ignore anything else
353
416
  continue;
354
417
  }
@@ -407,6 +470,8 @@ class QtTests {
407
470
  if (ctests) {
408
471
  for (let ctest of ctests) {
409
472
  let qtest = new QtTest(ctest.executablePath(), buildDirPath);
473
+ // Propagate environment from CTest metadata
474
+ qtest.environment = ctest.environment;
410
475
  this.qtTestExecutables.push(qtest);
411
476
  }
412
477
  }
@@ -453,8 +518,9 @@ class QtTests {
453
518
  }
454
519
  async dumpTestSlots() {
455
520
  for (var ex of this.qtTestExecutables) {
456
- if (!ex.slots)
521
+ if (!ex.slots) {
457
522
  await ex.parseAvailableSlots();
523
+ }
458
524
  console.log(ex.filename);
459
525
  if (ex.slots) {
460
526
  for (let slot of ex.slots) {
package/out/test.js CHANGED
@@ -10,23 +10,64 @@ 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
- let expected_executables = [
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",
29
+ "test/qt_test/build-dev/test_gtest",
18
30
  ];
19
- if (qt.qtTestExecutables.length != expected_executables.length) {
20
- console.error("Expected 3 executables, got " + qt.qtTestExecutables.length);
31
+ if (qt.qtTestExecutables.length !== expectedExecutables.length) {
32
+ console.error("Expected " +
33
+ expectedExecutables.length +
34
+ " executables, got " +
35
+ qt.qtTestExecutables.length);
36
+ process.exit(1);
37
+ }
38
+ // Verify that test_gtest is detected as a GTest
39
+ const gtestExe = qt.qtTestExecutables.find((e) => e.filenameWithoutExtension().endsWith("test_gtest"));
40
+ if (!gtestExe) {
41
+ console.error("Expected to find test_gtest executable after discovery");
21
42
  process.exit(1);
22
43
  }
44
+ if (!(await gtestExe.isGTest())) {
45
+ console.error("Expected test_gtest to be detected as a GTest");
46
+ process.exit(1);
47
+ }
48
+ console.log("PASS: test_gtest detected as GTest");
49
+ // Verify that test_gtest has no slots after parseAvailableSlots (GTest is skipped)
50
+ await gtestExe.parseAvailableSlots();
51
+ if (!gtestExe.slots || gtestExe.slots.length !== 0) {
52
+ console.error("Expected test_gtest to have 0 slots, got " +
53
+ (gtestExe.slots?.length ?? "null"));
54
+ process.exit(1);
55
+ }
56
+ console.log("PASS: test_gtest has 0 slots (no children)");
57
+ // Verify that a QtTest is not detected as a GTest
58
+ if (await test1Exe.isGTest()) {
59
+ console.error("Expected test1 to NOT be detected as a GTest");
60
+ process.exit(1);
61
+ }
62
+ console.log("PASS: test1 (QtTest) not misdetected as GTest");
23
63
  await qt.removeNonLinking();
24
64
  /// On macOS and Windows we don't have ldd or equivalent, so we can't check if the test links to QtTest
25
65
  /// Use the help way instead
26
66
  await qt.removeByRunningHelp();
27
- /// Remove the non-qttest executable from qt.qtTestExecutables
28
- qt.qtTestExecutables = qt.qtTestExecutables.filter((e) => !e.filenameWithoutExtension().endsWith("non_qttest"));
29
- if (qt.qtTestExecutables.length != 3) {
67
+ /// Remove the non-qttest and gtest executables from qt.qtTestExecutables
68
+ qt.qtTestExecutables = qt.qtTestExecutables.filter((e) => !e.filenameWithoutExtension().endsWith("non_qttest") &&
69
+ !e.filenameWithoutExtension().endsWith("test_gtest"));
70
+ if (qt.qtTestExecutables.length !== 3) {
30
71
  console.error("Expected 3 executables, at this point got " +
31
72
  qt.qtTestExecutables.length);
32
73
  process.exit(1);
@@ -34,8 +75,8 @@ async function runTests(buildDirPath) {
34
75
  // 1. Test that the executable test names are correct:
35
76
  var i = 0;
36
77
  for (var executable of qt.qtTestExecutables) {
37
- let expected = expected_executables[i];
38
- if (executable.relativeFilename() != expected) {
78
+ let expected = expectedExecutables[i];
79
+ if (executable.relativeFilename() !== expected) {
39
80
  console.error("Expected executable " +
40
81
  expected +
41
82
  ", got " +
@@ -46,7 +87,7 @@ async function runTests(buildDirPath) {
46
87
  }
47
88
  // 2. Test that the discovered slots are correct:
48
89
  await qt.dumpTestSlots();
49
- let expected_slots = {
90
+ let expectedSlots = {
50
91
  "test/qt_test/build-dev/test1": ["testA", "testB", "testC", "testXFAIL"],
51
92
  "test/qt_test/build-dev/test2": [
52
93
  "testD",
@@ -60,25 +101,25 @@ async function runTests(buildDirPath) {
60
101
  for (var executable of qt.qtTestExecutables) {
61
102
  var i = 0;
62
103
  for (let slot of executable.slots) {
63
- let expected_slot = expected_slots[executable.relativeFilename()][i];
64
- if (slot.name != expected_slot) {
65
- console.error("Expected slot " + expected_slot + ", got " + slot.name);
104
+ let expectedSlot = expectedSlots[executable.relativeFilename()][i];
105
+ if (slot.name !== expectedSlot) {
106
+ console.error("Expected slot " + expectedSlot + ", got " + slot.name);
66
107
  process.exit(1);
67
108
  }
68
109
  i++;
69
110
  }
70
111
  }
71
112
  // 3. Run the tests:
72
- let expected_success = [true, false, false];
113
+ let expectedSuccess = [true, false, false];
73
114
  var i = 0;
74
115
  for (var executable of qt.qtTestExecutables) {
75
116
  await executable.runTest();
76
117
  let wasSuccess = executable.lastExitCode === 0;
77
- if (wasSuccess && !expected_success[i]) {
118
+ if (wasSuccess && !expectedSuccess[i]) {
78
119
  console.error("Expected test to fail: " + executable.filename);
79
120
  process.exit(1);
80
121
  }
81
- else if (!wasSuccess && expected_success[i]) {
122
+ else if (!wasSuccess && expectedSuccess[i]) {
82
123
  console.error("Expected test to pass: " + executable.filename);
83
124
  process.exit(1);
84
125
  }
@@ -105,7 +146,7 @@ async function runTests(buildDirPath) {
105
146
  }
106
147
  // 5. Test executablesContainingSlot
107
148
  let executables = qt.executablesContainingSlot("testB");
108
- if (executables.length != 1) {
149
+ if (executables.length !== 1) {
109
150
  console.error("Expected 1 executable, got " + executables.length);
110
151
  process.exit(1);
111
152
  }
@@ -114,13 +155,13 @@ async function runTests(buildDirPath) {
114
155
  process.exit(1);
115
156
  }
116
157
  executables = qt.executablesContainingSlot("non_existing");
117
- if (executables.length != 0) {
158
+ if (executables.length !== 0) {
118
159
  console.error("Expected 0 executables, got " + executables.length);
119
160
  process.exit(1);
120
161
  }
121
162
  // 6. Run a slot that has XFAIL
122
163
  slot = qt.qtTestExecutables[0].slots[3];
123
- if (slot.name != "testXFAIL") {
164
+ if (slot.name !== "testXFAIL") {
124
165
  console.error("Expected slot name to be testXFAIL");
125
166
  process.exit(1);
126
167
  }
@@ -131,7 +172,7 @@ async function runTests(buildDirPath) {
131
172
  }
132
173
  // 7. Run a slot that has XPASS
133
174
  slot = qt.qtTestExecutables[1].slots[3];
134
- if (slot.name != "testXPASS") {
175
+ if (slot.name !== "testXPASS") {
135
176
  console.error("Expected slot name to be testXPASS");
136
177
  process.exit(1);
137
178
  }
@@ -142,7 +183,7 @@ async function runTests(buildDirPath) {
142
183
  }
143
184
  // 8. Run a slot that has both XFAIL and FAIL
144
185
  slot = qt.qtTestExecutables[1].slots[4];
145
- if (slot.name != "testMixXFAILWithFAIL") {
186
+ if (slot.name !== "testMixXFAILWithFAIL") {
146
187
  console.error("Expected slot name to be testMixXFAILWithFAIL");
147
188
  process.exit(1);
148
189
  }
@@ -158,29 +199,29 @@ async function runCodeModelTests(codeModelFile) {
158
199
  let codemodelJson = JSON.parse(codemodelStr);
159
200
  let cmake = new cmake_1.CMakeTests("random");
160
201
  let files = cmake.cppFilesForExecutable("/vscode-qttest/test/qt_test/build-dev/test1", codemodelJson);
161
- if (files.length != 1) {
202
+ if (files.length !== 1) {
162
203
  console.error("Expected 1 file, got " + files.length);
163
204
  process.exit(1);
164
205
  }
165
206
  let expected = "/vscode-qttest/test/qt_test/test1.cpp";
166
207
  let got = files[0].replace(/\\/g, "/");
167
- if (got != expected) {
208
+ if (got !== expected) {
168
209
  console.error("Expected " + expected + ", got " + got);
169
210
  process.exit(1);
170
211
  }
171
212
  let targetName = cmake.targetNameForExecutable("/vscode-qttest/test/qt_test/build-dev/test1", codemodelJson);
172
- if (targetName != "test1") {
213
+ if (targetName !== "test1") {
173
214
  console.error("Expected test1, got " + targetName);
174
215
  process.exit(1);
175
216
  }
176
217
  // test windows back slashes:
177
218
  files = cmake.cppFilesForExecutable("/vscode-qttest/test/qt_test/build-dev/test2", codemodelJson);
178
- if (files.length != 1) {
219
+ if (files.length !== 1) {
179
220
  console.error("Expected 1 file, got " + files.length);
180
221
  process.exit(1);
181
222
  }
182
223
  targetName = cmake.targetNameForExecutable("/vscode-qttest/test/qt_test/build-dev/test2", codemodelJson);
183
- if (targetName != "test2") {
224
+ if (targetName !== "test2") {
184
225
  console.error("Expected test2, got " + targetName);
185
226
  process.exit(1);
186
227
  }
@@ -205,7 +246,7 @@ async function runCodeModelTests(codeModelFile) {
205
246
  }
206
247
  targetName = cmake.targetNameForExecutable("/vscode-qttest/test/qt_test/build-dev/test3", codemodelJson,
207
248
  /*workaround=*/ true);
208
- if (targetName != "test3") {
249
+ if (targetName !== "test3") {
209
250
  console.error("Expected null, got " + targetName);
210
251
  process.exit(1);
211
252
  }
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() && !isLibrary(path_1.default.basename(childPath)) && isExecutable(childPath)) {
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.5.0",
3
+ "version": "2.6.1",
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": "^10.2.0",
36
+ "prettier": "3.8.1",
33
37
  "ts-node": "^10.9.2",
34
- "typescript": "^5.7.2"
38
+ "typescript": "^6.0.2",
39
+ "typescript-eslint": "^8.0.0"
35
40
  },
36
41
  "dependencies": {
37
- "tap-parser": "^16.0.1"
42
+ "tap-parser": "^18.3.0"
38
43
  }
39
44
  }