@iamsergio/qttest-utils 0.4.5 → 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
@@ -7,6 +7,7 @@ export declare class QtTest {
7
7
  readonly buildDirPath: string;
8
8
  vscodeTestItem: any | undefined;
9
9
  slots: QtTestSlot[] | null;
10
+ lastExitCode: number;
10
11
  constructor(filename: string, buildDirPath: string);
11
12
  get id(): string;
12
13
  get label(): string;
@@ -23,12 +24,17 @@ export declare class QtTest {
23
24
  */
24
25
  linksToQtTestLib(): Promise<boolean> | undefined;
25
26
  isQtTestViaHelp(): Promise<boolean | undefined>;
26
- 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;
27
31
  command(): {
28
32
  label: string;
29
33
  executablePath: string;
30
34
  args: string[];
31
35
  };
36
+ clearSubTestStates(): void;
37
+ updateSubTestStates(cwdDir: string, slot?: QtTestSlot): Promise<void>;
32
38
  }
33
39
  /**
34
40
  * Represents a single Qt test slot
@@ -37,6 +43,7 @@ export declare class QtTestSlot {
37
43
  name: string;
38
44
  parentQTest: QtTest;
39
45
  vscodeTestItem: any | undefined;
46
+ lastTestFailure: TestFailure | undefined;
40
47
  constructor(name: string, parent: QtTest);
41
48
  get id(): string;
42
49
  get absoluteFilePath(): string;
@@ -60,3 +67,8 @@ export declare class QtTests {
60
67
  dumpExecutablePaths(): void;
61
68
  dumpTestSlots(): Promise<void>;
62
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.5",
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
@@ -18,8 +18,12 @@ export class QtTest {
18
18
  /// Allows vscode extensions to associate with a test item
19
19
  vscodeTestItem: any | undefined;
20
20
 
21
+ /// The list of individual runnable test slots
21
22
  slots: QtTestSlot[] | null = null;
22
23
 
24
+ /// Set after running
25
+ lastExitCode: number = 0;
26
+
23
27
  constructor(filename: string, buildDirPath: string) {
24
28
  this.filename = filename;
25
29
  this.buildDirPath = buildDirPath;
@@ -138,22 +142,49 @@ export class QtTest {
138
142
  });
139
143
  }
140
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
+
141
157
  /// Runs this test
142
- public async runTest(slotName?: string, cwd: string = ""): Promise<boolean> {
158
+ public async runTest(slot?: QtTestSlot, cwd: string = ""): Promise<boolean> {
143
159
  let args: string[] = [];
144
- if (slotName) {
160
+ if (slot) {
145
161
  // Runs a single Qt test instead
146
- args = args.concat(slotName);
162
+ args = args.concat(slot.name);
163
+ } else {
164
+ this.clearSubTestStates();
147
165
  }
148
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
+
149
171
  return await new Promise((resolve, reject) => {
150
- let opts = cwd.length > 0 ? { cwd: cwd } : { cwd: this.buildDirPath };
151
- const child = spawn(this.filename, args, opts);
152
- child.stdout.on("data", (chunk) => {
153
- // chunk.toString()
154
- });
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);
155
187
 
156
- child.on("exit", (code) => {
157
188
  if (code === 0) {
158
189
  resolve(true);
159
190
  } else {
@@ -163,9 +194,71 @@ export class QtTest {
163
194
  });
164
195
  }
165
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
+
166
209
  public command(): { label: string, executablePath: string, args: string[] } {
167
210
  return { label: this.label, executablePath: this.filename, args: [] };
168
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
+ }
169
262
  }
170
263
 
171
264
  /**
@@ -180,6 +273,9 @@ export class QtTestSlot {
180
273
  /// Allows vscode extensions to associate with a test item
181
274
  vscodeTestItem: any | undefined;
182
275
 
276
+ /// Set after running
277
+ lastTestFailure: TestFailure | undefined;
278
+
183
279
  constructor(name: string, parent: QtTest) {
184
280
  this.name = name;
185
281
  this.parentQTest = parent;
@@ -194,7 +290,7 @@ export class QtTestSlot {
194
290
  }
195
291
 
196
292
  public async runTest(): Promise<boolean> {
197
- return this.parentQTest.runTest(this.name);
293
+ return this.parentQTest.runTest(this);
198
294
  }
199
295
 
200
296
  public command(): { label: string, executablePath: string, args: string[] } {
@@ -273,3 +369,10 @@ export class QtTests {
273
369
  }
274
370
  }
275
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