@iamsergio/qttest-utils 0.4.4 → 0.4.6

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/README.md CHANGED
@@ -4,4 +4,14 @@ A nodejs module for listing Qt Test executables and their individual test slots
4
4
 
5
5
  To be used by vscode extensions that implement the `Testing API`, but can also be used standalone for whatever reason ;).
6
6
 
7
- For example usage `src/example.ts`.
7
+
8
+ ## Example
9
+
10
+ ```
11
+ $ cd test/qt_test
12
+ $ cmake --preset=dev
13
+ $ cmake --build build-dev/
14
+ $ cd ../..
15
+ $ tsc
16
+ $ node out/example.js test/qt_test/build-dev
17
+ ```
package/a ADDED
@@ -0,0 +1,8 @@
1
+ const pattern = /at:\s+(.+?)::(.+?)\s+\((.+?):(\d+)\)/gm;
2
+ const matches = Array.from(data.matchAll(pattern));
3
+ const failingTests = matches.map(match => ({
4
+ name: match[2],
5
+ filePath: match[3],
6
+ lineNumber: parseInt(match[4]),
7
+ }));
8
+ resolve(failingTests);
package/foo ADDED
@@ -0,0 +1,15 @@
1
+ TAP version 13
2
+ # MyTest
3
+ ok 1 - initTestCase()
4
+ not ok 2 - testF()
5
+ ---
6
+ # failed
7
+ at: MyTest::testF() (/data/sources/vscode-test-extension/qttest-utils/test/qt_test/test2.cpp:13)
8
+ file: /data/sources/vscode-test-extension/qttest-utils/test/qt_test/test2.cpp
9
+ line: 13
10
+ ...
11
+ ok 3 - cleanupTestCase()
12
+ 1..3
13
+ # tests 3
14
+ # pass 2
15
+ # fail 1
package/out/example.js CHANGED
@@ -36,10 +36,37 @@ function example() {
36
36
  yield qt.removeNonLinking();
37
37
  // Example of filtering out by regexp:
38
38
  qt.removeMatching(/(tst_view|tst_window)/);
39
- // Example of filtering out by regexp (inverted):
40
- qt.maintainMatching(/(tst_docks|tst_qtwidgets|tst_multisplitter)/);
39
+ // Uncomment to see example of filtering out by regexp (inverted):
40
+ // qt.maintainMatching(/(tst_docks|tst_qtwidgets|tst_multisplitter)/);
41
41
  qt.dumpExecutablePaths();
42
- qt.dumpTestSlots();
42
+ yield qt.dumpTestSlots();
43
+ console.log("\nRunning tests...");
44
+ for (var executable of qt.qtTestExecutables) {
45
+ yield executable.runTest();
46
+ if (executable.lastExitCode === 0)
47
+ console.log(" PASS: " + executable.filename);
48
+ else
49
+ console.log(" FAIL: " + executable.filename + "; code=" + executable.lastExitCode);
50
+ for (let slot of executable.slots) {
51
+ if (slot.lastTestFailure) {
52
+ console.log(" failed slot=" + slot.name + "; path=" + slot.lastTestFailure.filePath + "; line=" + slot.lastTestFailure.lineNumber);
53
+ }
54
+ }
55
+ }
56
+ // Also run individual slots, just for example purposes:
57
+ console.log("\nRunning single tests...");
58
+ let slot = qt.qtTestExecutables[1].slots[0];
59
+ yield slot.runTest();
60
+ if (slot.lastTestFailure)
61
+ console.log(" FAIL:" + JSON.stringify(slot.lastTestFailure));
62
+ else
63
+ console.log(" PASS:");
64
+ let slot2 = qt.qtTestExecutables[1].slots[2];
65
+ yield slot2.runTest();
66
+ if (slot2.lastTestFailure)
67
+ console.log(" FAIL:" + JSON.stringify(slot2.lastTestFailure));
68
+ else
69
+ console.log(" PASS");
43
70
  });
44
71
  }
45
72
  example();
package/out/qttest.d.ts CHANGED
@@ -5,7 +5,9 @@
5
5
  export declare class QtTest {
6
6
  readonly filename: string;
7
7
  readonly buildDirPath: string;
8
+ vscodeTestItem: any | undefined;
8
9
  slots: QtTestSlot[] | null;
10
+ lastExitCode: number;
9
11
  constructor(filename: string, buildDirPath: string);
10
12
  get id(): string;
11
13
  get label(): string;
@@ -22,12 +24,17 @@ export declare class QtTest {
22
24
  */
23
25
  linksToQtTestLib(): Promise<boolean> | undefined;
24
26
  isQtTestViaHelp(): Promise<boolean | undefined>;
25
- runTest(slotName?: string, cwd?: string): Promise<boolean>;
27
+ slotByName(name: string): QtTestSlot | undefined;
28
+ runTest(slot?: QtTestSlot, cwd?: string): Promise<boolean>;
29
+ tapOutputFileName(slot?: QtTestSlot): string;
30
+ txtOutputFileName(slot?: QtTestSlot): string;
26
31
  command(): {
27
32
  label: string;
28
33
  executablePath: string;
29
34
  args: string[];
30
35
  };
36
+ clearSubTestStates(): void;
37
+ updateSubTestStates(cwdDir: string, slot?: QtTestSlot): Promise<void>;
31
38
  }
32
39
  /**
33
40
  * Represents a single Qt test slot
@@ -35,6 +42,8 @@ export declare class QtTest {
35
42
  export declare class QtTestSlot {
36
43
  name: string;
37
44
  parentQTest: QtTest;
45
+ vscodeTestItem: any | undefined;
46
+ lastTestFailure: TestFailure | undefined;
38
47
  constructor(name: string, parent: QtTest);
39
48
  get id(): string;
40
49
  get absoluteFilePath(): string;
@@ -58,3 +67,8 @@ export declare class QtTests {
58
67
  dumpExecutablePaths(): void;
59
68
  dumpTestSlots(): Promise<void>;
60
69
  }
70
+ export interface TestFailure {
71
+ name: string;
72
+ filePath: string;
73
+ lineNumber: number;
74
+ }
package/out/qttest.js CHANGED
@@ -49,7 +49,10 @@ const cmake_1 = require("./cmake");
49
49
  */
50
50
  class QtTest {
51
51
  constructor(filename, buildDirPath) {
52
+ /// The list of individual runnable test slots
52
53
  this.slots = null;
54
+ /// Set after running
55
+ this.lastExitCode = 0;
53
56
  this.filename = filename;
54
57
  this.buildDirPath = buildDirPath;
55
58
  }
@@ -159,34 +162,110 @@ class QtTest {
159
162
  });
160
163
  });
161
164
  }
165
+ slotByName(name) {
166
+ if (!this.slots)
167
+ return undefined;
168
+ for (let slot of this.slots) {
169
+ if (slot.name == name)
170
+ return slot;
171
+ }
172
+ return undefined;
173
+ }
162
174
  /// Runs this test
163
- runTest(slotName, cwd = "") {
175
+ runTest(slot, cwd = "") {
164
176
  return __awaiter(this, void 0, void 0, function* () {
165
177
  let args = [];
166
- if (slotName) {
178
+ if (slot) {
167
179
  // Runs a single Qt test instead
168
- args = args.concat(slotName);
180
+ args = args.concat(slot.name);
169
181
  }
182
+ else {
183
+ this.clearSubTestStates();
184
+ }
185
+ // log to file
186
+ args = args.concat("-o").concat(this.tapOutputFileName(slot) + ",tap");
187
+ args = args.concat("-o").concat(this.txtOutputFileName(slot) + ",txt");
170
188
  return yield new Promise((resolve, reject) => {
171
- let opts = cwd.length > 0 ? { cwd: cwd } : { cwd: this.buildDirPath };
172
- const child = (0, child_process_1.spawn)(this.filename, args, opts);
173
- child.stdout.on("data", (chunk) => {
174
- // chunk.toString()
175
- });
176
- child.on("exit", (code) => {
189
+ let cwdDir = cwd.length > 0 ? cwd : this.buildDirPath;
190
+ const child = (0, child_process_1.spawn)(this.filename, args, { cwd: cwdDir });
191
+ child.on("exit", (code) => __awaiter(this, void 0, void 0, function* () {
192
+ /// We can code even be null ?
193
+ if (code == undefined)
194
+ code = -1;
195
+ if (!slot) {
196
+ this.lastExitCode = code;
197
+ }
198
+ /// When running a QtTest executable, let's check which sub-tests failed
199
+ /// (So VSCode can show some error icon for each fail)
200
+ yield this.updateSubTestStates(cwdDir, slot);
177
201
  if (code === 0) {
178
202
  resolve(true);
179
203
  }
180
204
  else {
181
205
  resolve(false);
182
206
  }
183
- });
207
+ }));
184
208
  });
185
209
  });
186
210
  }
211
+ /// Using .tap so we don't have to use a separate XML library
212
+ /// .tap is plain text and a single regexp can catch the failing tests and line number
213
+ tapOutputFileName(slot) {
214
+ let slotName = slot ? ("_" + slot.name) : "";
215
+ return this.label + slotName + ".tap";
216
+ }
217
+ txtOutputFileName(slot) {
218
+ let slotName = slot ? ("_" + slot.name) : "";
219
+ return this.label + slotName + ".txt";
220
+ }
187
221
  command() {
188
222
  return { label: this.label, executablePath: this.filename, args: [] };
189
223
  }
224
+ clearSubTestStates() {
225
+ if (this.slots) {
226
+ for (let slot of this.slots) {
227
+ slot.lastTestFailure = undefined;
228
+ }
229
+ }
230
+ }
231
+ updateSubTestStates(cwdDir, slot) {
232
+ return __awaiter(this, void 0, void 0, function* () {
233
+ let tapFileName = cwdDir + "/" + this.tapOutputFileName(slot);
234
+ var failures = yield new Promise((resolve, reject) => {
235
+ fs.readFile(tapFileName, "utf8", (error, data) => {
236
+ if (error) {
237
+ console.log("Failed to read log file");
238
+ reject(error);
239
+ }
240
+ else {
241
+ // A fail line is something like:
242
+ // at: MyTest::testF() (/some/path/qttest-utils/test/qt_test/test2.cpp:13)
243
+ const pattern = /at:\s+(.+?)::(.+?)\(\)\s+\((.+?):(\d+)\)/gm;
244
+ const matches = Array.from(data.matchAll(pattern));
245
+ const failedResults = matches.map(match => ({
246
+ name: match[2],
247
+ filePath: match[3],
248
+ lineNumber: parseInt(match[4]),
249
+ }));
250
+ resolve(failedResults);
251
+ }
252
+ });
253
+ });
254
+ for (let failure of failures) {
255
+ if (slot && slot.name != failure.name) {
256
+ // We executed a single slot, ignore anything else
257
+ continue;
258
+ }
259
+ let failedSlot = this.slotByName(failure.name);
260
+ if (failedSlot) {
261
+ failedSlot.lastTestFailure = failure;
262
+ }
263
+ else {
264
+ console.log("Failed to find slot with name " + failure.name);
265
+ }
266
+ }
267
+ });
268
+ }
190
269
  }
191
270
  exports.QtTest = QtTest;
192
271
  /**
@@ -205,7 +284,7 @@ class QtTestSlot {
205
284
  }
206
285
  runTest() {
207
286
  return __awaiter(this, void 0, void 0, function* () {
208
- return this.parentQTest.runTest(this.name);
287
+ return this.parentQTest.runTest(this);
209
288
  });
210
289
  }
211
290
  command() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iamsergio/qttest-utils",
3
- "version": "0.4.4",
3
+ "version": "0.4.6",
4
4
  "description": "API for listing QtTest executables from a build directory and which individual test slots each executable contains. Useful for a Text Explorer VSCode extension.",
5
5
  "repository": {
6
6
  "type": "git",
package/src/example.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  import { CMakeTests, CMakeTest } from "./cmake";
6
6
  import { QtTest, QtTests } from "./qttest";
7
7
  import fs from 'fs';
8
+ import { exec } from "child_process";
8
9
 
9
10
  async function example() {
10
11
  const args = process.argv.slice(2)
@@ -31,11 +32,43 @@ async function example() {
31
32
  // Example of filtering out by regexp:
32
33
  qt.removeMatching(/(tst_view|tst_window)/);
33
34
 
34
- // Example of filtering out by regexp (inverted):
35
- qt.maintainMatching(/(tst_docks|tst_qtwidgets|tst_multisplitter)/);
35
+ // Uncomment to see example of filtering out by regexp (inverted):
36
+ // qt.maintainMatching(/(tst_docks|tst_qtwidgets|tst_multisplitter)/);
36
37
 
37
38
  qt.dumpExecutablePaths();
38
- qt.dumpTestSlots();
39
+ await qt.dumpTestSlots();
40
+
41
+ console.log("\nRunning tests...");
42
+ for (var executable of qt.qtTestExecutables) {
43
+ await executable.runTest();
44
+ if (executable.lastExitCode === 0)
45
+ console.log(" PASS: " + executable.filename);
46
+ else
47
+ console.log(" FAIL: " + executable.filename + "; code=" + executable.lastExitCode);
48
+ for (let slot of executable.slots!) {
49
+ if (slot.lastTestFailure) {
50
+ console.log(" failed slot=" + slot.name + "; path=" + slot.lastTestFailure.filePath + "; line=" + slot.lastTestFailure.lineNumber);
51
+ }
52
+ }
53
+ }
54
+
55
+ // Also run individual slots, just for example purposes:
56
+
57
+ console.log("\nRunning single tests...");
58
+ let slot = qt.qtTestExecutables[1].slots![0];
59
+ await slot.runTest();
60
+ if (slot.lastTestFailure)
61
+ console.log(" FAIL:" + JSON.stringify(slot.lastTestFailure));
62
+ else
63
+ console.log(" PASS:");
64
+
65
+ let slot2 = qt.qtTestExecutables[1].slots![2];
66
+ await slot2.runTest();
67
+ if (slot2.lastTestFailure)
68
+ console.log(" FAIL:" + JSON.stringify(slot2.lastTestFailure));
69
+ else
70
+ console.log(" PASS");
71
+
39
72
  }
40
73
 
41
74
  example();
package/src/qttest.ts CHANGED
@@ -15,8 +15,15 @@ export class QtTest {
15
15
  readonly filename: string;
16
16
  readonly buildDirPath: string;
17
17
 
18
+ /// Allows vscode extensions to associate with a test item
19
+ vscodeTestItem: any | undefined;
20
+
21
+ /// The list of individual runnable test slots
18
22
  slots: QtTestSlot[] | null = null;
19
23
 
24
+ /// Set after running
25
+ lastExitCode: number = 0;
26
+
20
27
  constructor(filename: string, buildDirPath: string) {
21
28
  this.filename = filename;
22
29
  this.buildDirPath = buildDirPath;
@@ -44,7 +51,7 @@ export class QtTest {
44
51
  return;
45
52
  }
46
53
 
47
- const child = spawn(this.filename, ["-functions"], {cwd: this.buildDirPath});
54
+ const child = spawn(this.filename, ["-functions"], { cwd: this.buildDirPath });
48
55
 
49
56
  child.stdout.on("data", (chunk) => {
50
57
  output += chunk.toString();
@@ -135,22 +142,49 @@ export class QtTest {
135
142
  });
136
143
  }
137
144
 
145
+ public slotByName(name: string): QtTestSlot | undefined {
146
+ if (!this.slots)
147
+ return undefined;
148
+
149
+ for (let slot of this.slots) {
150
+ if (slot.name == name)
151
+ return slot;
152
+ }
153
+
154
+ return undefined;
155
+ }
156
+
138
157
  /// Runs this test
139
- public async runTest(slotName?: string, cwd: string = ""): Promise<boolean> {
158
+ public async runTest(slot?: QtTestSlot, cwd: string = ""): Promise<boolean> {
140
159
  let args: string[] = [];
141
- if (slotName) {
160
+ if (slot) {
142
161
  // Runs a single Qt test instead
143
- args = args.concat(slotName);
162
+ args = args.concat(slot.name);
163
+ } else {
164
+ this.clearSubTestStates();
144
165
  }
145
166
 
167
+ // log to file
168
+ args = args.concat("-o").concat(this.tapOutputFileName(slot) + ",tap");
169
+ args = args.concat("-o").concat(this.txtOutputFileName(slot) + ",txt");
170
+
146
171
  return await new Promise((resolve, reject) => {
147
- let opts = cwd.length > 0 ? {cwd: cwd} : {cwd: this.buildDirPath};
148
- const child = spawn(this.filename, args, opts);
149
- child.stdout.on("data", (chunk) => {
150
- // chunk.toString()
151
- });
172
+ let cwdDir = cwd.length > 0 ? cwd : this.buildDirPath;
173
+ const child = spawn(this.filename, args, { cwd: cwdDir });
174
+
175
+ child.on("exit", async (code) => {
176
+
177
+ /// We can code even be null ?
178
+ if (code == undefined) code = -1;
179
+
180
+ if (!slot) {
181
+ this.lastExitCode = code;
182
+ }
183
+
184
+ /// When running a QtTest executable, let's check which sub-tests failed
185
+ /// (So VSCode can show some error icon for each fail)
186
+ await this.updateSubTestStates(cwdDir, slot);
152
187
 
153
- child.on("exit", (code) => {
154
188
  if (code === 0) {
155
189
  resolve(true);
156
190
  } else {
@@ -160,9 +194,71 @@ export class QtTest {
160
194
  });
161
195
  }
162
196
 
197
+ /// Using .tap so we don't have to use a separate XML library
198
+ /// .tap is plain text and a single regexp can catch the failing tests and line number
199
+ public tapOutputFileName(slot?: QtTestSlot): string {
200
+ let slotName = slot ? ("_" + slot.name) : "";
201
+ return this.label + slotName + ".tap";
202
+ }
203
+
204
+ public txtOutputFileName(slot?: QtTestSlot): string {
205
+ let slotName = slot ? ("_" + slot.name) : "";
206
+ return this.label + slotName + ".txt";
207
+ }
208
+
163
209
  public command(): { label: string, executablePath: string, args: string[] } {
164
210
  return { label: this.label, executablePath: this.filename, args: [] };
165
211
  }
212
+
213
+
214
+ public clearSubTestStates() {
215
+ if (this.slots) {
216
+ for (let slot of this.slots) {
217
+ slot.lastTestFailure = undefined;
218
+ }
219
+ }
220
+ }
221
+
222
+ public async updateSubTestStates(cwdDir: string, slot?: QtTestSlot) {
223
+
224
+ let tapFileName: string = cwdDir + "/" + this.tapOutputFileName(slot);
225
+
226
+ var failures = await new Promise<TestFailure[]>((resolve, reject) => {
227
+ fs.readFile(tapFileName, "utf8", (error, data) => {
228
+ if (error) {
229
+ console.log("Failed to read log file");
230
+ reject(error);
231
+ } else {
232
+ // A fail line is something like:
233
+ // at: MyTest::testF() (/some/path/qttest-utils/test/qt_test/test2.cpp:13)
234
+
235
+ const pattern = /at:\s+(.+?)::(.+?)\(\)\s+\((.+?):(\d+)\)/gm;
236
+ const matches = Array.from(data.matchAll(pattern));
237
+ const failedResults = matches.map(match => ({
238
+ name: match[2],
239
+ filePath: match[3],
240
+ lineNumber: parseInt(match[4]),
241
+ }));
242
+
243
+ resolve(failedResults);
244
+ }
245
+ });
246
+ });
247
+
248
+ for (let failure of failures) {
249
+ if (slot && slot.name != failure.name) {
250
+ // We executed a single slot, ignore anything else
251
+ continue;
252
+ }
253
+
254
+ let failedSlot = this.slotByName(failure.name);
255
+ if (failedSlot) {
256
+ failedSlot.lastTestFailure = failure;
257
+ } else {
258
+ console.log("Failed to find slot with name " + failure.name);
259
+ }
260
+ }
261
+ }
166
262
  }
167
263
 
168
264
  /**
@@ -174,6 +270,12 @@ export class QtTestSlot {
174
270
  // The QTest executable this slot belongs to
175
271
  parentQTest: QtTest;
176
272
 
273
+ /// Allows vscode extensions to associate with a test item
274
+ vscodeTestItem: any | undefined;
275
+
276
+ /// Set after running
277
+ lastTestFailure: TestFailure | undefined;
278
+
177
279
  constructor(name: string, parent: QtTest) {
178
280
  this.name = name;
179
281
  this.parentQTest = parent;
@@ -188,7 +290,7 @@ export class QtTestSlot {
188
290
  }
189
291
 
190
292
  public async runTest(): Promise<boolean> {
191
- return this.parentQTest.runTest(this.name);
293
+ return this.parentQTest.runTest(this);
192
294
  }
193
295
 
194
296
  public command(): { label: string, executablePath: string, args: string[] } {
@@ -267,3 +369,10 @@ export class QtTests {
267
369
  }
268
370
  }
269
371
  }
372
+
373
+ /// Represents a failure location
374
+ export interface TestFailure {
375
+ name: string;
376
+ filePath: string;
377
+ lineNumber: number;
378
+ }
@@ -0,0 +1,22 @@
1
+ # SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
2
+ # Author: Sergio Martins <sergio.martins@kdab.com>
3
+ # SPDX-License-Identifier: MIT
4
+
5
+ cmake_minimum_required(VERSION 3.12)
6
+ project(qttest)
7
+
8
+ find_package(Qt5Test 5.15 REQUIRED)
9
+ set(CMAKE_AUTOMOC ON)
10
+
11
+ add_executable(test1 test1.cpp)
12
+ add_executable(test2 test2.cpp)
13
+ add_executable(test3 test3.cpp)
14
+
15
+ target_link_libraries(test1 Qt5::Test)
16
+ target_link_libraries(test2 Qt5::Test)
17
+ target_link_libraries(test3 Qt5::Test)
18
+
19
+ enable_testing()
20
+ add_test(NAME test1 COMMAND test1)
21
+ add_test(NAME test2 COMMAND test2)
22
+ add_test(NAME test3 COMMAND test3)
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": 2,
3
+ "configurePresets": [
4
+ {
5
+ "name": "dev",
6
+ "displayName": "dev",
7
+ "generator": "Ninja",
8
+ "binaryDir": "${sourceDir}/build-dev",
9
+ "cacheVariables": {
10
+ "CMAKE_BUILD_TYPE": "Debug",
11
+ "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
12
+ }
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,18 @@
1
+ // SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group
2
+ // company <info@kdab.com> Author: Sergio Martins <sergio.martins@kdab.com>
3
+ // SPDX-License-Identifier: MIT
4
+
5
+ #include <QObject>
6
+ #include <QtTest>
7
+
8
+ class MyTest : public QObject {
9
+ Q_OBJECT
10
+ private Q_SLOTS:
11
+ void testA() {}
12
+ void testB() {}
13
+ void testC() {}
14
+ };
15
+
16
+ QTEST_MAIN(MyTest);
17
+
18
+ #include <test1.moc>
@@ -0,0 +1,18 @@
1
+ // SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group
2
+ // company <info@kdab.com> Author: Sergio Martins <sergio.martins@kdab.com>
3
+ // SPDX-License-Identifier: MIT
4
+
5
+ #include <QObject>
6
+ #include <QtTest>
7
+
8
+ class MyTest : public QObject {
9
+ Q_OBJECT
10
+ private Q_SLOTS:
11
+ void testD() {}
12
+ void testE() {}
13
+ void testF() { QFAIL("failed"); }
14
+ };
15
+
16
+ QTEST_MAIN(MyTest);
17
+
18
+ #include <test2.moc>
@@ -0,0 +1,18 @@
1
+ // SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group
2
+ // company <info@kdab.com> Author: Sergio Martins <sergio.martins@kdab.com>
3
+ // SPDX-License-Identifier: MIT
4
+
5
+ #include <QObject>
6
+ #include <QtTest>
7
+
8
+ class MyTest : public QObject {
9
+ Q_OBJECT
10
+ private Q_SLOTS:
11
+ void testG() {}
12
+ void testH() {}
13
+ void testI() {}
14
+ };
15
+
16
+ QTEST_MAIN(MyTest);
17
+
18
+ #include <test3.moc>
package/test1.log ADDED
@@ -0,0 +1,31 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <TestCase name="MyTest">
3
+ <Environment>
4
+ <QtVersion>5.15.2</QtVersion>
5
+ <QtBuild>Qt 5.15.2 (x86_64&#x002D;little_endian&#x002D;lp64 shared (dynamic) release build; by GCC 5.3.1 20160406 (Red Hat 5.3.1&#x002D;6))</QtBuild>
6
+ <QTestVersion>5.15.2</QTestVersion>
7
+ </Environment>
8
+ <TestFunction name="initTestCase">
9
+ <Incident type="pass" file="" line="0" />
10
+ <Duration msecs="0.312962"/>
11
+ </TestFunction>
12
+ <TestFunction name="testD">
13
+ <Incident type="pass" file="" line="0" />
14
+ <Duration msecs="0.010127"/>
15
+ </TestFunction>
16
+ <TestFunction name="testE">
17
+ <Incident type="pass" file="" line="0" />
18
+ <Duration msecs="0.005239"/>
19
+ </TestFunction>
20
+ <TestFunction name="testF">
21
+ <Incident type="fail" file="/data/sources/vscode&#x002D;test&#x002D;extension/qttest&#x002D;utils/test/qt_test/test2.cpp" line="13">
22
+ <Description><![CDATA[failed]]></Description>
23
+ </Incident>
24
+ <Duration msecs="0.018438"/>
25
+ </TestFunction>
26
+ <TestFunction name="cleanupTestCase">
27
+ <Incident type="pass" file="" line="0" />
28
+ <Duration msecs="0.00426"/>
29
+ </TestFunction>
30
+ <Duration msecs="0.432951"/>
31
+ </TestCase>
package/test1.log1 ADDED
@@ -0,0 +1,17 @@
1
+ TAP version 13
2
+ # MyTest
3
+ ok 1 - initTestCase()
4
+ ok 2 - testD()
5
+ ok 3 - testE()
6
+ not ok 4 - testF()
7
+ ---
8
+ # failed
9
+ at: MyTest::testF() (/data/sources/vscode-test-extension/qttest-utils/test/qt_test/test2.cpp:13)
10
+ file: /data/sources/vscode-test-extension/qttest-utils/test/qt_test/test2.cpp
11
+ line: 13
12
+ ...
13
+ ok 5 - cleanupTestCase()
14
+ 1..5
15
+ # tests 5
16
+ # pass 4
17
+ # fail 1