@iamsergio/qttest-utils 0.1.0 → 0.2.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,28 @@ 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
+ }
26
+ /**
27
+ * Represents a single Qt test slot
28
+ */
29
+ export declare class QtTestSlot {
30
+ name: string;
31
+ parentQTest: QtTest;
32
+ constructor(name: string, parent: QtTest);
33
+ get id(): string;
34
+ get absoluteFilePath(): string;
35
+ runTest(): Promise<boolean>;
22
36
  }
23
37
  /**
24
38
  * Represents the list of all QtTest executables in your project
25
39
  */
26
40
  export declare class QtTests {
27
- qtTestExacutables: QtTest[];
41
+ qtTestExecutables: QtTest[];
28
42
  discoverViaCMake(buildDirPath: string): Promise<void>;
29
43
  removeNonLinking(): Promise<void>;
44
+ removeByRunningHelp(): Promise<void>;
30
45
  removeMatching(regex: RegExp): void;
31
46
  maintainMatching(regex: RegExp): void;
32
47
  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,85 @@ 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
+ }
88
153
  }
89
154
  exports.QtTest = QtTest;
155
+ /**
156
+ * Represents a single Qt test slot
157
+ */
158
+ class QtTestSlot {
159
+ constructor(name, parent) {
160
+ this.name = name;
161
+ this.parentQTest = parent;
162
+ }
163
+ get id() {
164
+ return this.parentQTest.filename + this.name;
165
+ }
166
+ get absoluteFilePath() {
167
+ return this.parentQTest.filename;
168
+ }
169
+ runTest() {
170
+ return __awaiter(this, void 0, void 0, function* () {
171
+ return this.parentQTest.runTest(this.name);
172
+ });
173
+ }
174
+ }
175
+ exports.QtTestSlot = QtTestSlot;
90
176
  /**
91
177
  * Represents the list of all QtTest executables in your project
92
178
  */
93
179
  class QtTests {
94
180
  constructor() {
95
- this.qtTestExacutables = [];
181
+ this.qtTestExecutables = [];
96
182
  }
97
183
  discoverViaCMake(buildDirPath) {
98
184
  return __awaiter(this, void 0, void 0, function* () {
@@ -101,7 +187,7 @@ class QtTests {
101
187
  if (ctests) {
102
188
  for (let ctest of ctests) {
103
189
  let qtest = new QtTest(ctest.executablePath());
104
- this.qtTestExacutables.push(qtest);
190
+ this.qtTestExecutables.push(qtest);
105
191
  }
106
192
  }
107
193
  else {
@@ -119,38 +205,44 @@ class QtTests {
119
205
  return;
120
206
  }
121
207
  let acceptedExecutables = [];
122
- for (let ex of this.qtTestExacutables) {
208
+ for (let ex of this.qtTestExecutables) {
123
209
  let linksToQt = yield ex.linksToQtTestLib();
124
210
  // undefined or true is accepted
125
211
  if (linksToQt !== false) {
126
212
  acceptedExecutables.push(ex);
127
213
  }
128
- this.qtTestExacutables = acceptedExecutables;
214
+ this.qtTestExecutables = acceptedExecutables;
129
215
  }
130
216
  });
131
217
  }
218
+ removeByRunningHelp() {
219
+ return __awaiter(this, void 0, void 0, function* () {
220
+ this.qtTestExecutables = this.qtTestExecutables.filter((ex) => __awaiter(this, void 0, void 0, function* () { return yield ex.isQtTestViaHelp(); }));
221
+ });
222
+ }
132
223
  /// Removes any executable (from the list) that matches the specified regex
133
224
  removeMatching(regex) {
134
- let acceptedExecutables = [];
135
- this.qtTestExacutables = this.qtTestExacutables.filter((ex) => !regex.test(ex.filename));
225
+ this.qtTestExecutables = this.qtTestExecutables.filter((ex) => !regex.test(ex.filename));
136
226
  }
137
227
  /// Removes any executable (from the list) that doesn't match the specified regex
138
228
  maintainMatching(regex) {
139
- let acceptedExecutables = [];
140
- this.qtTestExacutables = this.qtTestExacutables.filter((ex) => regex.test(ex.filename));
229
+ this.qtTestExecutables = this.qtTestExecutables.filter((ex) => regex.test(ex.filename));
141
230
  }
142
231
  dumpExecutablePaths() {
143
- for (var ex of this.qtTestExacutables) {
232
+ for (var ex of this.qtTestExecutables) {
144
233
  console.log(ex.filename);
145
234
  }
146
235
  }
147
236
  dumpTestSlots() {
148
237
  return __awaiter(this, void 0, void 0, function* () {
149
- for (var ex of this.qtTestExacutables) {
150
- let names = yield ex.testNames();
238
+ for (var ex of this.qtTestExecutables) {
239
+ if (!ex.slots)
240
+ yield ex.parseAvailableSlots();
151
241
  console.log(ex.filename);
152
- for (let name of names) {
153
- console.log(" - " + name);
242
+ if (ex.slots) {
243
+ for (let slot of ex.slots) {
244
+ console.log(" - " + slot.name);
245
+ }
154
246
  }
155
247
  }
156
248
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@iamsergio/qttest-utils",
3
- "version": "0.1.0",
4
- "description": "API for determining if an executable is a QtTest and which tests it contains",
3
+ "version": "0.2.0",
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"
7
7
  },
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,89 @@ 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
+
149
+ /**
150
+ * Represents a single Qt test slot
151
+ */
152
+ export class QtTestSlot {
153
+ name: string;
154
+
155
+ // The QTest executable this slot belongs to
156
+ parentQTest: QtTest;
157
+
158
+ constructor(name: string, parent: QtTest) {
159
+ this.name = name;
160
+ this.parentQTest = parent;
161
+ }
162
+
163
+ public get id() {
164
+ return this.parentQTest.filename + this.name;
165
+ }
166
+
167
+ public get absoluteFilePath() {
168
+ return this.parentQTest.filename;
169
+ }
170
+
171
+ public async runTest(): Promise<boolean> {
172
+ return this.parentQTest.runTest(this.name);
173
+ }
82
174
  }
83
175
 
84
176
  /**
85
177
  * Represents the list of all QtTest executables in your project
86
178
  */
87
179
  export class QtTests {
88
- qtTestExacutables: QtTest[] = [];
180
+ qtTestExecutables: QtTest[] = [];
89
181
 
90
182
  async discoverViaCMake(buildDirPath: string) {
91
183
  var cmake = new CMakeTests(buildDirPath);
@@ -93,7 +185,7 @@ export class QtTests {
93
185
  if (ctests) {
94
186
  for (let ctest of ctests) {
95
187
  let qtest = new QtTest(ctest.executablePath());
96
- this.qtTestExacutables.push(qtest);
188
+ this.qtTestExecutables.push(qtest);
97
189
  }
98
190
  } else {
99
191
  console.error("Failed to retrieve ctests!");
@@ -108,40 +200,46 @@ export class QtTests {
108
200
  if (!isLinux) { return; }
109
201
 
110
202
  let acceptedExecutables: QtTest[] = [];
111
- for (let ex of this.qtTestExacutables) {
203
+ for (let ex of this.qtTestExecutables) {
112
204
  let linksToQt = await ex.linksToQtTestLib();
113
205
  // undefined or true is accepted
114
206
  if (linksToQt !== false) {
115
207
  acceptedExecutables.push(ex);
116
208
  }
117
- this.qtTestExacutables = acceptedExecutables;
209
+ this.qtTestExecutables = acceptedExecutables;
118
210
  }
119
211
  }
120
212
 
213
+ public async removeByRunningHelp() {
214
+ this.qtTestExecutables = this.qtTestExecutables.filter(async (ex) => await ex.isQtTestViaHelp());
215
+ }
216
+
121
217
  /// Removes any executable (from the list) that matches the specified regex
122
218
  public removeMatching(regex: RegExp) {
123
- let acceptedExecutables: QtTest[] = [];
124
- this.qtTestExacutables = this.qtTestExacutables.filter((ex) => !regex.test(ex.filename));
219
+ this.qtTestExecutables = this.qtTestExecutables.filter((ex) => !regex.test(ex.filename));
125
220
  }
126
221
 
127
222
  /// Removes any executable (from the list) that doesn't match the specified regex
128
223
  public maintainMatching(regex: RegExp) {
129
- let acceptedExecutables: QtTest[] = [];
130
- this.qtTestExacutables = this.qtTestExacutables.filter((ex) => regex.test(ex.filename));
224
+ this.qtTestExecutables = this.qtTestExecutables.filter((ex) => regex.test(ex.filename));
131
225
  }
132
226
 
133
227
  public dumpExecutablePaths() {
134
- for (var ex of this.qtTestExacutables) {
228
+ for (var ex of this.qtTestExecutables) {
135
229
  console.log(ex.filename);
136
230
  }
137
231
  }
138
232
 
139
233
  public async dumpTestSlots() {
140
- for (var ex of this.qtTestExacutables) {
141
- let names = await ex.testNames();
234
+ for (var ex of this.qtTestExecutables) {
235
+ if (!ex.slots)
236
+ await ex.parseAvailableSlots();
237
+
142
238
  console.log(ex.filename);
143
- for (let name of names) {
144
- console.log(" - " + name);
239
+ if (ex.slots) {
240
+ for (let slot of ex.slots) {
241
+ console.log(" - " + slot.name);
242
+ }
145
243
  }
146
244
  }
147
245
  }