diff --git a/CHANGELOG.md b/CHANGELOG.md index 468e9ec7..6ce0d534 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.2.5] + +### Fixed + +- Source file path resolution +- Bug related to automatic test reloading + ## [2.2.4] - 2018-12-04 Updated README.md diff --git a/src/C2AllTestSuiteInfo.ts b/src/C2AllTestSuiteInfo.ts index cff0b2eb..7cbd595f 100644 --- a/src/C2AllTestSuiteInfo.ts +++ b/src/C2AllTestSuiteInfo.ts @@ -2,7 +2,6 @@ // vscode-catch2-test-adapter was written by Mate Pek, and is placed in the // public domain. The author hereby disclaims copyright to this source code. -import { SpawnOptions } from 'child_process'; import { inspect } from 'util'; import * as vscode from 'vscode'; import { TestEvent, TestInfo, TestLoadFinishedEvent, TestLoadStartedEvent, TestRunFinishedEvent, TestRunStartedEvent, TestSuiteEvent, TestSuiteInfo } from 'vscode-test-adapter-api'; @@ -63,7 +62,8 @@ export class C2AllTestSuiteInfo implements TestSuiteInfo, vscode.Disposable { }, (reason: any) => { this._loadFinishedEmitter.fire(); - this.log.warn(inspect(reason)); + this.log.error(inspect(reason)); + debugger; throw reason; }); } @@ -121,17 +121,20 @@ export class C2AllTestSuiteInfo implements TestSuiteInfo, vscode.Disposable { return undefined; } - createChildSuite(label: string, execPath: string, execOptions: SpawnOptions): - C2TestSuiteInfo { - const suite = new C2TestSuiteInfo(label, this, execPath, execOptions); + hasSuite(suite: C2TestSuiteInfo): boolean { + return this.children.indexOf(suite) != -1; + } + + insertChildSuite(suite: C2TestSuiteInfo): boolean { + if (this.children.indexOf(suite) != -1) return false; let i = this.children.findIndex((v: C2TestSuiteInfo) => { return suite.label.trim().localeCompare(v.label.trim()) < 0; }); + if (i == -1) i = this.children.length; this.children.splice(i, 0, suite); - - return suite; + return true; } cancel(): void { diff --git a/src/C2ExecutableInfo.ts b/src/C2ExecutableInfo.ts index 0bd63b02..90deefc9 100644 --- a/src/C2ExecutableInfo.ts +++ b/src/C2ExecutableInfo.ts @@ -84,26 +84,26 @@ export class C2ExecutableInfo implements vscode.Disposable { for (let i = 0; i < fileUris.length; i++) { const file = fileUris[i]; - const suite = this._addFile(file); - this._executables.set(file.fsPath, suite); + const suite = this._createSuiteByUri(file); - await suite.reloadChildren().catch((reason: any) => { + await suite.reloadChildren().then(() => { + this._executables.set(file.fsPath, suite); + this._allTests.insertChildSuite(suite); + }, (reason: any) => { this._allTests.log.warn( 'Couldn\'t load suite: ' + inspect([reason, suite])); if (suite.catch2Version !== undefined) this._allTests.log.error('but it was a Catch2 executable'); - - this._allTests.removeChild(suite); }); } this._uniquifySuiteNames(); } - private _addFile(file: vscode.Uri) { + private _createSuiteByUri(file: vscode.Uri): C2TestSuiteInfo { const wsUri = this._allTests.workspaceFolder.uri; - let resolvedName = this.name; + let resolvedLabel = this.name; let resolvedCwd = this.cwd; let resolvedEnv: { [prop: string]: string } = this.env; try { @@ -131,10 +131,10 @@ export class C2ExecutableInfo implements vscode.Disposable { ['${ext3Filename}', ext3Filename], ['${base3Filename}', base3Filename], ]; - resolvedName = resolveVariables(this.name, varToValue); - if (resolvedName.match(/\$\{.*\}/)) + resolvedLabel = resolveVariables(this.name, varToValue); + if (resolvedLabel.match(/\$\{.*\}/)) this._allTests.log.warn( - 'Possibly unresolved variable: ' + resolvedName); + 'Possibly unresolved variable: ' + resolvedLabel); resolvedCwd = path.normalize(resolveVariables(this.cwd, varToValue)); if (resolvedCwd.match(/\$\{.*\}/)) this._allTests.log.warn('Possibly unresolved variable: ' + resolvedCwd); @@ -143,63 +143,67 @@ export class C2ExecutableInfo implements vscode.Disposable { this._allTests.log.error(inspect([e, this])); } - const suite = this._allTests.createChildSuite( - resolvedName, file.fsPath, { cwd: resolvedCwd, env: resolvedEnv }); - - return suite; + return new C2TestSuiteInfo(resolvedLabel, this._allTests, + file.fsPath, { cwd: resolvedCwd, env: resolvedEnv }); } private _handleEverything(uri: vscode.Uri) { + const isRunning = this._lastEventArrivedAt.get(uri.fsPath) !== undefined; + if (isRunning) return; + + this._lastEventArrivedAt.set(uri.fsPath, Date.now()); + let suite = this._executables.get(uri.fsPath); if (suite == undefined) { this._allTests.log.info('new suite: ' + uri.fsPath); - suite = this._addFile(uri); - this._executables.set(uri.fsPath, suite); - this._uniquifySuiteNames(); + suite = this._createSuiteByUri(uri); } - const isRunning = this._lastEventArrivedAt.get(uri.fsPath) !== undefined; - - this._lastEventArrivedAt.set(uri.fsPath, Date.now()); - - if (isRunning) return; - const x = (exists: boolean, delay: number): Promise => { let lastEventArrivedAt = this._lastEventArrivedAt.get(uri.fsPath); if (lastEventArrivedAt === undefined) { this._allTests.log.error('assert in ' + __filename); debugger; return Promise.resolve(); - } - if (Date.now() - lastEventArrivedAt! > this._allTests.execWatchTimeout) { + } else if (Date.now() - lastEventArrivedAt! > this._allTests.execWatchTimeout) { this._allTests.log.info('refresh timeout: ' + uri.fsPath); - return this._allTests.sendLoadEvents(() => { - this._lastEventArrivedAt.delete(uri.fsPath); - this._executables.delete(uri.fsPath); - this._allTests.removeChild(suite!); + this._lastEventArrivedAt.delete(uri.fsPath); + if (this._allTests.hasSuite(suite!)) { + return this._allTests.sendLoadEvents(() => { + this._executables.delete(uri.fsPath); + this._allTests.removeChild(suite!); + return Promise.resolve(); + }); + } else { return Promise.resolve(); - }); + } } else if (exists) { - return this._allTests - .sendLoadEvents(() => { + // note: here we reload children outside start-finished event + // it seems ok now, but maybe it is a problem, if insertChildSuite == false + return suite!.reloadChildren().then(() => { + return this._allTests.sendLoadEvents(() => { + if (this._allTests.insertChildSuite(suite!)) { + this._executables.set(uri.fsPath, suite!); + this._uniquifySuiteNames(); + } this._lastEventArrivedAt.delete(uri.fsPath); - return suite!.reloadChildren().catch((reason: any) => { - this._allTests.log.error( - 'suite should exists, but there is some problem under reloading: ' + - inspect([reason, uri])); - return x(false, Math.min(delay * 2, 2000)); - }); - }) - .then(() => { + return Promise.resolve(); + }).then(() => { this._allTests.autorunEmitter.fire(); }); - } - return promisify(setTimeout)(Math.min(delay * 2, 2000)).then(() => { - return c2fs.existsAsync(uri.fsPath).then((exists: boolean) => { - return x(exists, Math.min(delay * 2, 2000)); + }, (reason: any) => { + this._allTests.log.warn( + 'Problem under reloadChildren: ' + inspect([reason, uri.fsPath, suite])); + return x(false, Math.min(delay * 2, 2000)); }); - }); + } else { + return promisify(setTimeout)(Math.min(delay * 2, 2000)).then(() => { + return c2fs.existsAsync(uri.fsPath).then((exists: boolean) => { + return x(exists, Math.min(delay * 2, 2000)); + }); + }); + } }; x(false, 64); diff --git a/src/C2TestSuiteInfo.ts b/src/C2TestSuiteInfo.ts index 9fb02f06..9701df33 100644 --- a/src/C2TestSuiteInfo.ts +++ b/src/C2TestSuiteInfo.ts @@ -385,14 +385,31 @@ export class C2TestSuiteInfo implements TestSuiteInfo { const fileLine = lines[i++].substr(4); const match = fileLine.match(/(?:(.+):([0-9]+)|(.+)\(([0-9]+)\))/); + if (match && match.length == 5) { - filePath = match[1] ? match[1] : match[3]; - filePath = - path.resolve(path.dirname(this.execPath), filePath); - if (!c2fs.existsSync(filePath) && this.execOptions.cwd) { - const r = path.resolve(this.execOptions.cwd, filePath); - if (c2fs.existsSync(r)) filePath = r; + const matchedPath = match[1] ? match[1] : match[3]; + filePath = path.resolve(this.allTests.workspaceFolder.uri.fsPath, matchedPath); + try { + if (!c2fs.existsSync(filePath) && this.execOptions.cwd) { + filePath = path.resolve(this.execOptions.cwd, matchedPath); + } + if (!c2fs.existsSync(filePath)) { + let parent = path.dirname(this.execPath); + filePath = path.resolve(parent, matchedPath); + let parentParent = path.dirname(parent); + while (!c2fs.existsSync(filePath) && parent != parentParent) { + parent = parentParent; + filePath = path.resolve(parent, matchedPath); + parentParent = path.dirname(parent); + } + } + if (!c2fs.existsSync(filePath)) { + filePath = matchedPath; + } + } catch (e) { + filePath = path.resolve(this.allTests.workspaceFolder.uri.fsPath, matchedPath); } + line = Number(match[2] ? match[2] : match[4]); } } diff --git a/src/test/example1.ts b/src/test/example1.ts index a58c3662..7a7840ec 100644 --- a/src/test/example1.ts +++ b/src/test/example1.ts @@ -1,7 +1,7 @@ import * as assert from 'assert'; import * as path from 'path'; import * as vscode from 'vscode'; -import {TestInfo, TestSuiteInfo} from 'vscode-test-adapter-api'; +import { TestInfo, TestSuiteInfo } from 'vscode-test-adapter-api'; assert.notEqual(vscode.workspace.workspaceFolders, undefined); assert.equal(vscode.workspace.workspaceFolders!.length, 1); @@ -11,17 +11,14 @@ const workspaceFolderUri = vscode.workspace.workspaceFolders![0].uri; export const example1 = new class { readonly suite1 = new class { readonly execPath = - vscode.Uri.file(path.join(workspaceFolderUri.path, 'execPath1')).fsPath; + vscode.Uri.file(path.join(workspaceFolderUri.path, 'execPath1')).fsPath; readonly t1 = new class { readonly fullTestName = 's1t1'; assert(label: string, test: TestInfo, uniqeIdContainer?: Set) { assert.equal(test.type, 'test'); assert.equal(test.label, label); - assert.equal( - test.file, - vscode.Uri.file(path.join(workspaceFolderUri.path, 'suite1.cpp')) - .fsPath); + assert.equal(test.file, 'suite1.cpp'); assert.equal(test.line, 7 - 1); assert.ok(test.skipped == undefined || test.skipped === false); if (uniqeIdContainer != undefined) { @@ -68,10 +65,7 @@ export const example1 = new class { assert(label: string, test: TestInfo, uniqeIdContainer?: Set) { assert.equal(test.type, 'test'); assert.equal(test.label, label); - assert.equal( - test.file, - vscode.Uri.file(path.join(workspaceFolderUri.path, 'suite1.cpp')) - .fsPath); + assert.equal(test.file, 'suite1.cpp'); assert.equal(test.line, 13 - 1); assert.ok(test.skipped == undefined || test.skipped === false); if (uniqeIdContainer != undefined) { @@ -134,13 +128,13 @@ export const example1 = new class { [ ['[.],*', '--verbosity', 'high', '--list-tests', '--use-colour', 'no'], 'Matching test cases:\n' + - ' s1t1\n' + - ' suite1.cpp:7\n' + - ' tag1\n' + - ' s1t2\n' + - ' suite1.cpp:13\n' + - ' tag1\n' + - '2 matching test cases\n\n' + ' s1t1\n' + + ' suite1.cpp:7\n' + + ' tag1\n' + + ' s1t2\n' + + ' suite1.cpp:13\n' + + ' tag1\n' + + '2 matching test cases\n\n' ], [ ['--reporter', 'xml', '--durations', 'yes'], @@ -196,21 +190,18 @@ export const example1 = new class { ]; assert( - label: string, childLabels: string[], suite: TestSuiteInfo, - uniqeIdContainer?: Set) { + label: string, childLabels: string[], suite: TestSuiteInfo, + uniqeIdContainer?: Set) { assert.equal(suite.type, 'suite'); assert.equal(suite.label, label); - assert.equal( - suite.file, - vscode.Uri.file(path.join(workspaceFolderUri.path, 'suite1.cpp')) - .fsPath); + assert.equal(suite.file, 'suite1.cpp'); assert.equal(suite.line, 0); assert.equal(suite.children.length, 2); assert.equal(childLabels.length, suite.children.length); this.t1.assert( - childLabels[0], suite.children[0], uniqeIdContainer); + childLabels[0], suite.children[0], uniqeIdContainer); this.t2.assert( - childLabels[1], suite.children[1], uniqeIdContainer); + childLabels[1], suite.children[1], uniqeIdContainer); if (uniqeIdContainer != undefined) { assert.ok(!uniqeIdContainer.has(suite.id)); uniqeIdContainer.add(suite.id); @@ -220,17 +211,14 @@ export const example1 = new class { readonly suite2 = new class { readonly execPath = - vscode.Uri.file(path.join(workspaceFolderUri.path, 'execPath2')).fsPath; + vscode.Uri.file(path.join(workspaceFolderUri.path, 'execPath2')).fsPath; readonly t1 = new class { readonly fullTestName = 's2t1'; assert(label: string, test: TestInfo, uniqeIdContainer?: Set) { assert.equal(test.type, 'test'); assert.equal(test.label, label); - assert.equal( - test.file, - vscode.Uri.file(path.join(workspaceFolderUri.path, 'suite2.cpp')) - .fsPath); + assert.equal(test.file, 'suite2.cpp'); assert.equal(test.line, 7 - 1); assert.ok(test.skipped == undefined || test.skipped === false); if (uniqeIdContainer != undefined) { @@ -277,10 +265,7 @@ export const example1 = new class { assert(label: string, test: TestInfo, uniqeIdContainer?: Set) { assert.equal(test.type, 'test'); assert.equal(test.label, label); - assert.equal( - test.file, - vscode.Uri.file(path.join(workspaceFolderUri.path, 'suite2.cpp')) - .fsPath); + assert.equal(test.file, 'suite2.cpp'); assert.equal(test.line, 13 - 1); assert.ok(test.skipped === true); if (uniqeIdContainer != undefined) { @@ -327,10 +312,7 @@ export const example1 = new class { assert(label: string, test: TestInfo, uniqeIdContainer?: Set) { assert.equal(test.type, 'test'); assert.equal(test.label, label); - assert.equal( - test.file, - vscode.Uri.file(path.join(workspaceFolderUri.path, 'suite2.cpp')) - .fsPath); + assert.equal(test.file, 'suite2.cpp'); assert.equal(test.line, 19 - 1); assert.ok(test.skipped == undefined || test.skipped === false); if (uniqeIdContainer != undefined) { @@ -389,23 +371,20 @@ export const example1 = new class { }; assert( - label: string, childLabels: string[], suite: TestSuiteInfo, - uniqeIdContainer?: Set) { + label: string, childLabels: string[], suite: TestSuiteInfo, + uniqeIdContainer?: Set) { assert.equal(suite.type, 'suite'); assert.equal(suite.label, label); - assert.equal( - suite.file, - vscode.Uri.file(path.join(workspaceFolderUri.path, 'suite2.cpp')) - .fsPath); + assert.equal(suite.file, 'suite2.cpp'); assert.equal(suite.line, 0); assert.equal(suite.children.length, 3); assert.equal(childLabels.length, suite.children.length); this.t1.assert( - childLabels[0], suite.children[0], uniqeIdContainer); + childLabels[0], suite.children[0], uniqeIdContainer); this.t2.assert( - childLabels[1], suite.children[1], uniqeIdContainer); + childLabels[1], suite.children[1], uniqeIdContainer); this.t3.assert( - childLabels[2], suite.children[2], uniqeIdContainer); + childLabels[2], suite.children[2], uniqeIdContainer); if (uniqeIdContainer != undefined) { assert.ok(!uniqeIdContainer.has(suite.id)); uniqeIdContainer.add(suite.id); @@ -417,17 +396,17 @@ export const example1 = new class { [ ['[.],*', '--verbosity', 'high', '--list-tests', '--use-colour', 'no'], 'Matching test cases:\n' + - ' s2t1\n' + - ' suite2.cpp:7\n' + - ' tag1\n' + - ' s2t2\n' + - ' suite2.cpp:13\n' + - ' tag1\n' + - ' [.]\n' + - ' s2t3\n' + - ' suite2.cpp:19\n' + - ' tag1\n' + - '3 matching test cases\n\n' + ' s2t1\n' + + ' suite2.cpp:7\n' + + ' tag1\n' + + ' s2t2\n' + + ' suite2.cpp:13\n' + + ' tag1\n' + + ' [.]\n' + + ' s2t3\n' + + ' suite2.cpp:19\n' + + ' tag1\n' + + '3 matching test cases\n\n' ], [ ['--reporter', 'xml', '--durations', 'yes'], @@ -484,7 +463,7 @@ export const example1 = new class { readonly suite3 = new class { readonly execPath = - vscode.Uri.file(path.join(workspaceFolderUri.path, 'execPath3')).fsPath; + vscode.Uri.file(path.join(workspaceFolderUri.path, 'execPath3')).fsPath; readonly outputs: [string[], string][] = [