@iamsergio/qttest-utils 0.1.1 → 0.3.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.
@@ -0,0 +1,11 @@
1
+ {
2
+ "folders": [
3
+ {
4
+ "path": "."
5
+ },
6
+ {
7
+ "path": "../vscode-extension-kdab-qttest/"
8
+ }
9
+ ],
10
+ "settings": {}
11
+ }
package/out/example.js CHANGED
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  const qttest_1 = require("./qttest");
19
19
  const fs_1 = __importDefault(require("fs"));
20
- function test() {
20
+ function example() {
21
21
  return __awaiter(this, void 0, void 0, function* () {
22
22
  const args = process.argv.slice(2);
23
23
  if (args.length != 1) {
@@ -30,12 +30,16 @@ function test() {
30
30
  process.exit(1);
31
31
  }
32
32
  let qt = new qttest_1.QtTests();
33
+ // Gather all tests that would be executed by CTest:
33
34
  yield qt.discoverViaCMake(buildDirPath);
35
+ // Filter-out the ones that don't link to QtTest (doctests and such)
34
36
  yield qt.removeNonLinking();
37
+ // Example of filtering out by regexp:
35
38
  qt.removeMatching(/(tst_view|tst_window)/);
39
+ // Example of filtering out by regexp (inverted):
36
40
  qt.maintainMatching(/(tst_docks|tst_qtwidgets|tst_multisplitter)/);
37
41
  qt.dumpExecutablePaths();
38
42
  qt.dumpTestSlots();
39
43
  });
40
44
  }
41
- test();
45
+ example();
package/out/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { CMakeTests, CMakeTest } from "./cmake";
2
- import { QtTests, QtTest } from "./qttest";
2
+ import { QtTests, QtTest, QtTestSlot } from "./qttest";
3
3
  declare const qttest: {
4
4
  QtTests: typeof QtTests;
5
5
  QtTest: typeof QtTest;
6
+ QtTestSlot: typeof QtTestSlot;
6
7
  CMakeTests: typeof CMakeTests;
7
8
  CMakeTest: typeof CMakeTest;
8
9
  };
package/out/index.js CHANGED
@@ -6,6 +6,6 @@ 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, CMakeTests: cmake_1.CMakeTests, CMakeTest: cmake_1.CMakeTest
9
+ QtTests: qttest_1.QtTests, QtTest: qttest_1.QtTest, QtTestSlot: qttest_1.QtTestSlot, CMakeTests: cmake_1.CMakeTests, CMakeTest: cmake_1.CMakeTest
10
10
  };
11
11
  exports.default = qttest;
package/out/qttest.d.ts CHANGED
@@ -4,13 +4,14 @@
4
4
  */
5
5
  export declare class QtTest {
6
6
  readonly filename: string;
7
+ slots: QtTestSlot[] | null;
7
8
  constructor(filename: string);
9
+ get id(): string;
10
+ get label(): string;
8
11
  /**
9
- * Calls "./yourqttest -functions" and returns the result.
10
- *
11
- * @returns The name of the individual test slots present in the exactuable
12
+ * Calls "./yourqttest -functions" and stores the results in the slots property.
12
13
  */
13
- testNames(): Promise<string[]>;
14
+ parseAvailableSlots(): Promise<void>;
14
15
  /**
15
16
  * Returns whether this executable links to libQtTest.so.
16
17
  *
@@ -19,14 +20,38 @@ export declare class QtTest {
19
20
  * Only implemented for Linux. Returns undefined on other platforms.
20
21
  */
21
22
  linksToQtTestLib(): Promise<boolean> | undefined;
23
+ isQtTestViaHelp(): Promise<boolean | undefined>;
24
+ runTest(slotName?: string): Promise<boolean>;
25
+ command(): {
26
+ label: string;
27
+ executablePath: string;
28
+ args: string[];
29
+ };
30
+ }
31
+ /**
32
+ * Represents a single Qt test slot
33
+ */
34
+ export declare class QtTestSlot {
35
+ name: string;
36
+ parentQTest: QtTest;
37
+ constructor(name: string, parent: QtTest);
38
+ get id(): string;
39
+ get absoluteFilePath(): string;
40
+ runTest(): Promise<boolean>;
41
+ command(): {
42
+ label: string;
43
+ executablePath: string;
44
+ args: string[];
45
+ };
22
46
  }
23
47
  /**
24
48
  * Represents the list of all QtTest executables in your project
25
49
  */
26
50
  export declare class QtTests {
27
- qtTestExacutables: QtTest[];
51
+ qtTestExecutables: QtTest[];
28
52
  discoverViaCMake(buildDirPath: string): Promise<void>;
29
53
  removeNonLinking(): Promise<void>;
54
+ removeByRunningHelp(): Promise<void>;
30
55
  removeMatching(regex: RegExp): void;
31
56
  maintainMatching(regex: RegExp): void;
32
57
  dumpExecutablePaths(): void;
package/out/qttest.js CHANGED
@@ -11,9 +11,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  step((generator = generator.apply(thisArg, _arguments || [])).next());
12
12
  });
13
13
  };
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
14
17
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.QtTests = exports.QtTest = void 0;
18
+ exports.QtTests = exports.QtTestSlot = exports.QtTest = void 0;
16
19
  const child_process_1 = require("child_process");
20
+ const path_1 = __importDefault(require("path"));
17
21
  const cmake_1 = require("./cmake");
18
22
  /**
19
23
  * Represents a single QtTest executable.
@@ -21,16 +25,21 @@ const cmake_1 = require("./cmake");
21
25
  */
22
26
  class QtTest {
23
27
  constructor(filename) {
28
+ this.slots = null;
24
29
  this.filename = filename;
25
30
  }
31
+ get id() {
32
+ return this.filename;
33
+ }
34
+ get label() {
35
+ return path_1.default.basename(this.filename);
36
+ }
26
37
  /**
27
- * Calls "./yourqttest -functions" and returns the result.
28
- *
29
- * @returns The name of the individual test slots present in the exactuable
38
+ * Calls "./yourqttest -functions" and stores the results in the slots property.
30
39
  */
31
- testNames() {
40
+ parseAvailableSlots() {
32
41
  return __awaiter(this, void 0, void 0, function* () {
33
- let subtests = [];
42
+ let slotNames = [];
34
43
  let output = "";
35
44
  yield new Promise((resolve, reject) => {
36
45
  const child = (0, child_process_1.spawn)(this.filename, ["-functions"]);
@@ -39,17 +48,23 @@ class QtTest {
39
48
  });
40
49
  child.on("exit", (code) => {
41
50
  if (code === 0) {
42
- subtests = subtests.concat(output.split("\n"));
43
- subtests = subtests.map(entry => entry.trim().replace("()", ""));
44
- subtests = subtests.filter(entry => entry.length > 0);
45
- resolve(subtests);
51
+ slotNames = slotNames.concat(output.split("\n"));
52
+ slotNames = slotNames.map(entry => entry.trim().replace("()", ""));
53
+ slotNames = slotNames.filter(entry => entry.length > 0);
54
+ if (slotNames.length > 0) {
55
+ this.slots = [];
56
+ for (var slotName of slotNames) {
57
+ var slot = new QtTestSlot(slotName, this);
58
+ this.slots.push(slot);
59
+ }
60
+ }
61
+ resolve(slotNames);
46
62
  }
47
63
  else {
48
64
  reject(new Error("Failed to run -functions"));
49
65
  }
50
66
  });
51
67
  });
52
- return subtests;
53
68
  });
54
69
  }
55
70
  /**
@@ -85,14 +100,91 @@ class QtTest {
85
100
  });
86
101
  });
87
102
  }
103
+ /// Returns whether this test is a QtTest by running it with -help and checking if the help text looks familiar
104
+ /// Note that if this is not a QtTest it might not run help and instead execute the test itself
105
+ isQtTestViaHelp() {
106
+ return __awaiter(this, void 0, void 0, function* () {
107
+ return yield new Promise((resolve, reject) => {
108
+ const child = (0, child_process_1.spawn)(this.filename, ["-help"]);
109
+ let output = "";
110
+ let result = false;
111
+ child.stdout.on("data", (chunk) => {
112
+ if (!result) {
113
+ if (chunk.toString().includes("[testfunction[:testdata]]")) {
114
+ result = true;
115
+ }
116
+ }
117
+ });
118
+ child.on("exit", (code) => {
119
+ if (code === 0) {
120
+ resolve(result);
121
+ }
122
+ else {
123
+ resolve(false);
124
+ }
125
+ });
126
+ });
127
+ });
128
+ }
129
+ /// Runs this test
130
+ runTest(slotName) {
131
+ return __awaiter(this, void 0, void 0, function* () {
132
+ let args = [];
133
+ if (slotName) {
134
+ // Runs a single Qt test instead
135
+ args = args.concat(slotName);
136
+ }
137
+ return yield new Promise((resolve, reject) => {
138
+ const child = (0, child_process_1.spawn)(this.filename, args);
139
+ child.stdout.on("data", (chunk) => {
140
+ // chunk.toString()
141
+ });
142
+ child.on("exit", (code) => {
143
+ if (code === 0) {
144
+ resolve(true);
145
+ }
146
+ else {
147
+ resolve(false);
148
+ }
149
+ });
150
+ });
151
+ });
152
+ }
153
+ command() {
154
+ return { label: this.label, executablePath: this.filename, args: [] };
155
+ }
88
156
  }
89
157
  exports.QtTest = QtTest;
158
+ /**
159
+ * Represents a single Qt test slot
160
+ */
161
+ class QtTestSlot {
162
+ constructor(name, parent) {
163
+ this.name = name;
164
+ this.parentQTest = parent;
165
+ }
166
+ get id() {
167
+ return this.parentQTest.filename + this.name;
168
+ }
169
+ get absoluteFilePath() {
170
+ return this.parentQTest.filename;
171
+ }
172
+ runTest() {
173
+ return __awaiter(this, void 0, void 0, function* () {
174
+ return this.parentQTest.runTest(this.name);
175
+ });
176
+ }
177
+ command() {
178
+ return { label: this.name, executablePath: this.absoluteFilePath, args: [this.name] };
179
+ }
180
+ }
181
+ exports.QtTestSlot = QtTestSlot;
90
182
  /**
91
183
  * Represents the list of all QtTest executables in your project
92
184
  */
93
185
  class QtTests {
94
186
  constructor() {
95
- this.qtTestExacutables = [];
187
+ this.qtTestExecutables = [];
96
188
  }
97
189
  discoverViaCMake(buildDirPath) {
98
190
  return __awaiter(this, void 0, void 0, function* () {
@@ -101,7 +193,7 @@ class QtTests {
101
193
  if (ctests) {
102
194
  for (let ctest of ctests) {
103
195
  let qtest = new QtTest(ctest.executablePath());
104
- this.qtTestExacutables.push(qtest);
196
+ this.qtTestExecutables.push(qtest);
105
197
  }
106
198
  }
107
199
  else {
@@ -119,38 +211,44 @@ class QtTests {
119
211
  return;
120
212
  }
121
213
  let acceptedExecutables = [];
122
- for (let ex of this.qtTestExacutables) {
214
+ for (let ex of this.qtTestExecutables) {
123
215
  let linksToQt = yield ex.linksToQtTestLib();
124
216
  // undefined or true is accepted
125
217
  if (linksToQt !== false) {
126
218
  acceptedExecutables.push(ex);
127
219
  }
128
- this.qtTestExacutables = acceptedExecutables;
220
+ this.qtTestExecutables = acceptedExecutables;
129
221
  }
130
222
  });
131
223
  }
224
+ removeByRunningHelp() {
225
+ return __awaiter(this, void 0, void 0, function* () {
226
+ this.qtTestExecutables = this.qtTestExecutables.filter((ex) => __awaiter(this, void 0, void 0, function* () { return yield ex.isQtTestViaHelp(); }));
227
+ });
228
+ }
132
229
  /// Removes any executable (from the list) that matches the specified regex
133
230
  removeMatching(regex) {
134
- let acceptedExecutables = [];
135
- this.qtTestExacutables = this.qtTestExacutables.filter((ex) => !regex.test(ex.filename));
231
+ this.qtTestExecutables = this.qtTestExecutables.filter((ex) => !regex.test(ex.filename));
136
232
  }
137
233
  /// Removes any executable (from the list) that doesn't match the specified regex
138
234
  maintainMatching(regex) {
139
- let acceptedExecutables = [];
140
- this.qtTestExacutables = this.qtTestExacutables.filter((ex) => regex.test(ex.filename));
235
+ this.qtTestExecutables = this.qtTestExecutables.filter((ex) => regex.test(ex.filename));
141
236
  }
142
237
  dumpExecutablePaths() {
143
- for (var ex of this.qtTestExacutables) {
238
+ for (var ex of this.qtTestExecutables) {
144
239
  console.log(ex.filename);
145
240
  }
146
241
  }
147
242
  dumpTestSlots() {
148
243
  return __awaiter(this, void 0, void 0, function* () {
149
- for (var ex of this.qtTestExacutables) {
150
- let names = yield ex.testNames();
244
+ for (var ex of this.qtTestExecutables) {
245
+ if (!ex.slots)
246
+ yield ex.parseAvailableSlots();
151
247
  console.log(ex.filename);
152
- for (let name of names) {
153
- console.log(" - " + name);
248
+ if (ex.slots) {
249
+ for (let slot of ex.slots) {
250
+ console.log(" - " + slot.name);
251
+ }
154
252
  }
155
253
  }
156
254
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iamsergio/qttest-utils",
3
- "version": "0.1.1",
3
+ "version": "0.3.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
  "scripts": {
6
6
  "build": "tsc"
package/src/index.ts CHANGED
@@ -3,10 +3,10 @@
3
3
  // SPDX-License-Identifier: MIT
4
4
 
5
5
  import { CMakeTests, CMakeTest } from "./cmake";
6
- import { QtTests, QtTest } from "./qttest";
6
+ import { QtTests, QtTest, QtTestSlot } from "./qttest";
7
7
 
8
8
  const qttest = {
9
- QtTests, QtTest, CMakeTests, CMakeTest
9
+ QtTests, QtTest, QtTestSlot, CMakeTests, CMakeTest
10
10
  };
11
11
 
12
12
  export default qttest;
package/src/qttest.ts CHANGED
@@ -3,6 +3,7 @@
3
3
  // SPDX-License-Identifier: MIT
4
4
 
5
5
  import { spawn } from "child_process";
6
+ import path from "path";
6
7
  import { CMakeTests } from "./cmake";
7
8
 
8
9
  /**
@@ -11,17 +12,25 @@ import { CMakeTests } from "./cmake";
11
12
  */
12
13
  export class QtTest {
13
14
  readonly filename: string;
15
+ slots: QtTestSlot[] | null = null;
16
+
14
17
  constructor(filename: string) {
15
18
  this.filename = filename;
16
19
  }
17
20
 
21
+ public get id() {
22
+ return this.filename;
23
+ }
24
+
25
+ public get label() {
26
+ return path.basename(this.filename);
27
+ }
28
+
18
29
  /**
19
- * Calls "./yourqttest -functions" and returns the result.
20
- *
21
- * @returns The name of the individual test slots present in the exactuable
30
+ * Calls "./yourqttest -functions" and stores the results in the slots property.
22
31
  */
23
- public async testNames(): Promise<string[]> {
24
- let subtests: string[] = [];
32
+ public async parseAvailableSlots(): Promise<void> {
33
+ let slotNames: string[] = [];
25
34
  let output = "";
26
35
 
27
36
  await new Promise((resolve, reject) => {
@@ -33,17 +42,24 @@ export class QtTest {
33
42
 
34
43
  child.on("exit", (code) => {
35
44
  if (code === 0) {
36
- subtests = subtests.concat(output.split("\n"));
37
- subtests = subtests.map(entry => entry.trim().replace("()", ""));
38
- subtests = subtests.filter(entry => entry.length > 0);
39
- resolve(subtests);
45
+ slotNames = slotNames.concat(output.split("\n"));
46
+ slotNames = slotNames.map(entry => entry.trim().replace("()", ""));
47
+ slotNames = slotNames.filter(entry => entry.length > 0);
48
+
49
+ if (slotNames.length > 0) {
50
+ this.slots = [];
51
+ for (var slotName of slotNames) {
52
+ var slot = new QtTestSlot(slotName, this);
53
+ this.slots.push(slot);
54
+ }
55
+ }
56
+
57
+ resolve(slotNames);
40
58
  } else {
41
59
  reject(new Error("Failed to run -functions"));
42
60
  }
43
61
  });
44
62
  });
45
-
46
- return subtests;
47
63
  }
48
64
 
49
65
  /**
@@ -79,13 +95,97 @@ export class QtTest {
79
95
  });
80
96
  });
81
97
  }
98
+
99
+ /// Returns whether this test is a QtTest by running it with -help and checking if the help text looks familiar
100
+ /// Note that if this is not a QtTest it might not run help and instead execute the test itself
101
+ public async isQtTestViaHelp(): Promise<boolean | undefined> {
102
+ return await new Promise((resolve, reject) => {
103
+ const child = spawn(this.filename, ["-help"]);
104
+ let output = "";
105
+ let result = false;
106
+ child.stdout.on("data", (chunk) => {
107
+ if (!result) {
108
+ if (chunk.toString().includes("[testfunction[:testdata]]")) {
109
+ result = true;
110
+ }
111
+ }
112
+ });
113
+
114
+ child.on("exit", (code) => {
115
+ if (code === 0) {
116
+ resolve(result);
117
+ } else {
118
+ resolve(false);
119
+ }
120
+ });
121
+ });
122
+ }
123
+
124
+ /// Runs this test
125
+ public async runTest(slotName?: string): Promise<boolean> {
126
+ let args: string[] = [];
127
+ if (slotName) {
128
+ // Runs a single Qt test instead
129
+ args = args.concat(slotName);
130
+ }
131
+
132
+ return await new Promise((resolve, reject) => {
133
+ const child = spawn(this.filename, args);
134
+ child.stdout.on("data", (chunk) => {
135
+ // chunk.toString()
136
+ });
137
+
138
+ child.on("exit", (code) => {
139
+ if (code === 0) {
140
+ resolve(true);
141
+ } else {
142
+ resolve(false);
143
+ }
144
+ });
145
+ });
146
+ }
147
+
148
+ public command(): { label: string, executablePath: string, args: string[] } {
149
+ return { label: this.label, executablePath: this.filename, args: [] };
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Represents a single Qt test slot
155
+ */
156
+ export class QtTestSlot {
157
+ name: string;
158
+
159
+ // The QTest executable this slot belongs to
160
+ parentQTest: QtTest;
161
+
162
+ constructor(name: string, parent: QtTest) {
163
+ this.name = name;
164
+ this.parentQTest = parent;
165
+ }
166
+
167
+ public get id() {
168
+ return this.parentQTest.filename + this.name;
169
+ }
170
+
171
+ public get absoluteFilePath() {
172
+ return this.parentQTest.filename;
173
+ }
174
+
175
+ public async runTest(): Promise<boolean> {
176
+ return this.parentQTest.runTest(this.name);
177
+ }
178
+
179
+ public command(): { label: string, executablePath: string, args: string[] } {
180
+ return { label: this.name, executablePath: this.absoluteFilePath, args: [this.name] };
181
+ }
82
182
  }
83
183
 
84
184
  /**
85
185
  * Represents the list of all QtTest executables in your project
86
186
  */
87
187
  export class QtTests {
88
- qtTestExacutables: QtTest[] = [];
188
+ qtTestExecutables: QtTest[] = [];
89
189
 
90
190
  async discoverViaCMake(buildDirPath: string) {
91
191
  var cmake = new CMakeTests(buildDirPath);
@@ -93,7 +193,7 @@ export class QtTests {
93
193
  if (ctests) {
94
194
  for (let ctest of ctests) {
95
195
  let qtest = new QtTest(ctest.executablePath());
96
- this.qtTestExacutables.push(qtest);
196
+ this.qtTestExecutables.push(qtest);
97
197
  }
98
198
  } else {
99
199
  console.error("Failed to retrieve ctests!");
@@ -108,40 +208,46 @@ export class QtTests {
108
208
  if (!isLinux) { return; }
109
209
 
110
210
  let acceptedExecutables: QtTest[] = [];
111
- for (let ex of this.qtTestExacutables) {
211
+ for (let ex of this.qtTestExecutables) {
112
212
  let linksToQt = await ex.linksToQtTestLib();
113
213
  // undefined or true is accepted
114
214
  if (linksToQt !== false) {
115
215
  acceptedExecutables.push(ex);
116
216
  }
117
- this.qtTestExacutables = acceptedExecutables;
217
+ this.qtTestExecutables = acceptedExecutables;
118
218
  }
119
219
  }
120
220
 
221
+ public async removeByRunningHelp() {
222
+ this.qtTestExecutables = this.qtTestExecutables.filter(async (ex) => await ex.isQtTestViaHelp());
223
+ }
224
+
121
225
  /// Removes any executable (from the list) that matches the specified regex
122
226
  public removeMatching(regex: RegExp) {
123
- let acceptedExecutables: QtTest[] = [];
124
- this.qtTestExacutables = this.qtTestExacutables.filter((ex) => !regex.test(ex.filename));
227
+ this.qtTestExecutables = this.qtTestExecutables.filter((ex) => !regex.test(ex.filename));
125
228
  }
126
229
 
127
230
  /// Removes any executable (from the list) that doesn't match the specified regex
128
231
  public maintainMatching(regex: RegExp) {
129
- let acceptedExecutables: QtTest[] = [];
130
- this.qtTestExacutables = this.qtTestExacutables.filter((ex) => regex.test(ex.filename));
232
+ this.qtTestExecutables = this.qtTestExecutables.filter((ex) => regex.test(ex.filename));
131
233
  }
132
234
 
133
235
  public dumpExecutablePaths() {
134
- for (var ex of this.qtTestExacutables) {
236
+ for (var ex of this.qtTestExecutables) {
135
237
  console.log(ex.filename);
136
238
  }
137
239
  }
138
240
 
139
241
  public async dumpTestSlots() {
140
- for (var ex of this.qtTestExacutables) {
141
- let names = await ex.testNames();
242
+ for (var ex of this.qtTestExecutables) {
243
+ if (!ex.slots)
244
+ await ex.parseAvailableSlots();
245
+
142
246
  console.log(ex.filename);
143
- for (let name of names) {
144
- console.log(" - " + name);
247
+ if (ex.slots) {
248
+ for (let slot of ex.slots) {
249
+ console.log(" - " + slot.name);
250
+ }
145
251
  }
146
252
  }
147
253
  }