Skip to content

Commit

Permalink
Merge pull request #14 from matepek/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
matepek authored Oct 24, 2018
2 parents 730c8ef + d015f06 commit 9be32c6
Show file tree
Hide file tree
Showing 19 changed files with 3,157 additions and 1,290 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
node_modules
out
*.vsix
Expand Down
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
sudo: false
language: node_js
node_js:
- "10"

os:
- osx
Expand All @@ -14,7 +17,6 @@ before_install:
install:
- npm install
- npm run compile
#- npm run vscode:prepublish

script:
- npm test --silent
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.2.0]

### Added

- Configuration: `catch2TestExplorer.defaultExecWatchTimeout`: Test executables are being watched. In case of one compiles too much this variable can help with it.

## [1.1.2]

Bugfix release.
Bugfix release

## [1.1.1]

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This adapter doesn't support everything.
| `catch2TestExplorer.defaultEnv` | Default environment variables to be set when running the tests, if it isn't provided in 'executables'. (Resolves: ${workspaceFolder}) |
| `catch2TestExplorer.defaultCwd` | The working directory where the test is run (relative to the workspace folder or absolue path), if it isn't provided in 'executables'. (Resolves: ${workspaceFolder}) |
| `catch2TestExplorer.defaultRngSeed` | Specify a seed for the Random Number Generator. For details see [Catch2 documentation](https://github.com/catchorg/Catch2/blob/master/docs/command-line.md#rng-seed) |
| `catch2TestExplorer.defaultExecWatchTimeout` | Test executables are being watched. In case of one compiles too much this variable can help with it. |
| `catch2TestExplorer.workerMaxNumber` | The variable maximize the number of the parallel test execution. |
| `catch2TestExplorer.enableSourceDecoration` | Sets the source code decorations: Errored lines will be highlited. |
| `catch2TestExplorer.debugConfigurationTemplate` | Set the necessary debug configuraitons and the debug button will work. Details: [below](#catch2TestExplorer.debugConfigurationTemplate) |
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
"name": "vscode-catch2-test-adapter",
"displayName": "Catch2 Test Explorer",
"description": "Run your Catch2 tests in the Sidebar of Visual Studio Code",
"icon": "icon.png",
"icon": "resources/icon.png",
"author": "Mate Pek",
"publisher": "matepek",
"version": "1.1.2",
"version": "1.2.0",
"license": "Unlicense",
"homepage": "https://github.com/matepek/vscode-catch2-test-adapter",
"repository": {
Expand All @@ -29,7 +29,7 @@
"scripts": {
"postinstall": "node ./node_modules/vscode/bin/install",
"reinstall": "rimraf node_modules package-lock.json && npm install",
"clean": "rimraf out vscode-google-test-adapter-*.vsix",
"clean": "rimraf out",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"rebuild": "npm run clean && npm run build",
Expand Down Expand Up @@ -120,6 +120,14 @@
"default": null,
"scope": "resource"
},
"catch2TestExplorer.defaultExecWatchTimeout": {
"description": "Test executables are being watched. In case of one compiles too much this variable can help with it.",
"type": [
"number"
],
"default": 10000,
"scope": "resource"
},
"catch2TestExplorer.workerMaxNumber": {
"description": "The variable maximize the number of the parallel test execution.",
"type": "number",
Expand Down
File renamed without changes
Binary file added resources/logo.xcf
Binary file not shown.
5 changes: 3 additions & 2 deletions src/C2AllTestSuiteInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,10 @@ export class C2AllTestSuiteInfo implements TestSuiteInfo {
}

const ps: Promise<void>[] = [];
this.children.forEach(child => {
for (let i = 0; i < this.children.length; i++) {
const child = this.children[i];
ps.push(child.run(testSet));
});
}

if (testSet.size > 0) {
this.adapter.log.error('Some tests have remained.');
Expand Down
101 changes: 65 additions & 36 deletions src/C2TestAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// 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 * as fs from 'fs';
import * as path from 'path';
import {inspect, promisify} from 'util';
import * as vscode from 'vscode';
import {TestAdapter, TestEvent, TestLoadFinishedEvent, TestLoadStartedEvent, TestRunFinishedEvent, TestRunStartedEvent, TestSuiteEvent} from 'vscode-test-adapter-api';
import * as util from 'vscode-test-adapter-util';
Expand All @@ -20,7 +20,7 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
TestSuiteEvent|TestEvent>();
private readonly autorunEmitter = new vscode.EventEmitter<void>();

private readonly watchers: Map<string, fs.FSWatcher> = new Map();
private readonly watchers: Map<string, c2fs.FSWatcher> = new Map();
private isRunning: number = 0;
private isDebugging: boolean = false;

Expand Down Expand Up @@ -80,6 +80,9 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
this.disposables.forEach(d => {
d.dispose();
});
this.watchers.forEach((v) => {
v.close();
});
}

get testStates(): vscode.Event<TestRunStartedEvent|TestRunFinishedEvent|
Expand All @@ -105,40 +108,60 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
watcher.close();
}
try {
watcher = fs.watch(suite.execPath);
watcher = c2fs.watch(suite.execPath);
this.watchers.set(suite.execPath, watcher);
const allTests = this.allTests; // alltest may has changed

watcher.on('change', (eventType: string, filename: string) => {
// need some time here:
const waitAndThenTry = (remainingIteration: number, delay: number) => {
if (remainingIteration == 0) {
watcher!.close();
this.watchers.delete(suite.execPath);
this.testsEmitter.fire({type: 'started'});
allTests.removeChild(suite);
this.testsEmitter.fire({type: 'finished', suite: this.allTests});
} else if (!fs.existsSync(suite.execPath)) {
setTimeout(
waitAndThenTry, delay,
[remainingIteration - 1, Math.max(delay * 2, 2000)]);
} else {
this.testsEmitter.fire({type: 'started'});
suite.reloadChildren().then(() => {
this.testsEmitter.fire({type: 'finished', suite: this.allTests});
});
}
};
const x =
(exists: boolean, startTime: number, timeout: number,
delay: number): Promise<void> => {
if ((Date.now() - startTime) > timeout) {
watcher!.close();
this.watchers.delete(suite.execPath);
this.testsEmitter.fire({type: 'started'});
allTests.removeChild(suite);
this.testsEmitter.fire(
{type: 'finished', suite: this.allTests});
return Promise.resolve();
} else if (exists) {
this.testsEmitter.fire({type: 'started'});
return suite.reloadChildren().then(
() => {
this.testsEmitter.fire(
{type: 'finished', suite: this.allTests});
},
(err: any) => {
this.testsEmitter.fire(
{type: 'finished', suite: this.allTests});
this.log.warn(inspect(err));
return x(
false, startTime, timeout, Math.min(delay * 2, 2000));
});
}
return promisify(setTimeout)(Math.min(delay * 2, 2000))
.then(() => {
return c2fs.existsAsync(suite.execPath)
.then((exists: boolean) => {
return x(
exists, startTime, timeout,
Math.min(delay * 2, 2000));
});
});
};

// change event can arrive during debug session on osx (why?)
if (!this.isDebugging) {
waitAndThenTry(10, 128);
// TODO filter multiple events and dont mess with 'load'
x(false, Date.now(),
this.getDefaultExecWatchTimeout(this.getConfiguration()), 64);
}
});
} catch (e) {
this.log.warn('watcher couldn\'t watch: ' + suite.execPath);
}
return suite.reloadChildren().catch((e) => {
return suite.reloadChildren().catch((err: any) => {
this.log.warn(inspect(err));
this.allTests.removeChild(suite);
});
}
Expand Down Expand Up @@ -359,6 +382,11 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
return config.get<null|string|number>('defaultRngSeed', null);
}

private getDefaultExecWatchTimeout(config: vscode.WorkspaceConfiguration):
number {
return config.get<number>('defaultExecWatchTimeout', 10000);
}

private getWorkerMaxNumber(config: vscode.WorkspaceConfiguration): number {
return config.get<number>('workerMaxNumber', 4);
}
Expand Down Expand Up @@ -387,7 +415,7 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
return config.get<boolean>('enableSourceDecoration', true);
}

private getExecutables(config: vscode.WorkspaceConfiguration):
private async getExecutables(config: vscode.WorkspaceConfiguration):
Promise<ExecutableConfig[]> {
const globalWorkingDirectory = this.getDefaultCwd(config);

Expand All @@ -400,7 +428,7 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
return path.isAbsolute(p) ? p : this.resolveRelPath(p);
};

const addObject = (o: Object): void => {
const addObject = async(o: Object): Promise<void> => {
const name: string =
o.hasOwnProperty('name') ? (<any>o)['name'] : '${dirname} : ${name}';
if (!o.hasOwnProperty('path') || (<any>o)['path'] === null) {
Expand All @@ -421,11 +449,12 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
false;

if (regex.length > 0) {
const recursiveAdd = (directory: string): void => {
const recursiveAdd = async(directory: string): Promise<void> => {
const children = c2fs.readdirSync(directory);
children.forEach(child => {
for (let i = 0; i < children.length; ++i) {
const child = children[i];
const childPath = path.resolve(directory, child);
const childStat = c2fs.statSync(childPath);
const childStat = await c2fs.statAsync(childPath);
if (childPath.match(regex) && childStat.isFile()) {
let resolvedName = name + ' : ' + child;
let resolvedCwd = cwd;
Expand All @@ -451,14 +480,14 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
executables.push(new ExecutableConfig(
resolvedName, childPath, regex, fullPath(resolvedCwd), env));
} else if (childStat.isDirectory() && regexRecursive) {
recursiveAdd(childPath);
await recursiveAdd(childPath);
}
});
}
};
try {
const stat = c2fs.statSync(p);
const stat = await c2fs.statAsync(p);
if (stat.isDirectory()) {
recursiveAdd(p);
await recursiveAdd(p);
} else if (stat.isFile()) {
executables.push(new ExecutableConfig(name, p, regex, cwd, env));
} else {
Expand Down Expand Up @@ -492,16 +521,16 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
'', globalWorkingDirectory, []));
}
} else {
addObject(configExecs[i]);
await addObject(configExecs[i]);
}
}
} else if (configExecs instanceof Object) {
addObject(configExecs);
await addObject(configExecs);
} else {
throw 'Catch2 config error: wrong type: executables';
}

return this.filterVerifiedCatch2TestExecutables(executables);
return this.filterVerifiedCatch2TestExecutables(await executables);
}

verifyIsCatch2TestExecutable(path: string): Promise<boolean> {
Expand Down
7 changes: 5 additions & 2 deletions src/C2TestInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ export class C2TestInfo implements TestInfo {
}

getEscapedTestName(): string {
let t = this.testNameFull.replace(',', '\\,').replace('[', '\\[');
if (t[0] == ' ') t = '*' + t.substr(1);
let t = this.testNameFull;
t = t.replace(/,/g, '\\,')
t = t.replace(/\[/g, '\\[');
t = t.replace(/\*/g, '\\*');
if (t.startsWith(' ')) t = '*' + t.substr(1);
return t;
}

Expand Down
30 changes: 15 additions & 15 deletions src/C2TestSuiteInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
// public domain. The author hereby disclaims copyright to this source code.

import {ChildProcess, spawn, SpawnOptions} from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import {promisify} from 'util';
import {TestEvent, TestSuiteEvent, TestSuiteInfo} from 'vscode-test-adapter-api';
import * as xml2js from 'xml2js';

Expand Down Expand Up @@ -82,17 +80,19 @@ export class C2TestSuiteInfo implements TestSuiteInfo {
this.proc = undefined;

if (tests.delete(this.id)) {
this.children.forEach(c => {
for (let i = 0; i < this.children.length; i++) {
const c = this.children[i];
tests.delete(c.id);
});
}

return this.runInner('all');
} else {
let childrenToRun: C2TestInfo[] = [];

this.children.forEach(c => {
for (let i = 0; i < this.children.length; i++) {
const c = this.children[i];
if (tests.delete(c.id)) childrenToRun.push(c);
});
}

if (childrenToRun.length == 0) return Promise.resolve();

Expand All @@ -115,18 +115,20 @@ export class C2TestSuiteInfo implements TestSuiteInfo {
const execParams: string[] = [];
if (childrenToRun != 'all') {
let testNames: string[] = [];
childrenToRun.forEach(c => {
for (let i = 0; i < childrenToRun.length; i++) {
const c = childrenToRun[i];
/*',' has special meaning */
testNames.push(c.getEscapedTestName());
});
}
execParams.push(testNames.join(','));
} else {
this.children.forEach(c => {
for (let i = 0; i < this.children.length; i++) {
const c = this.children[i];
if (c.skipped) {
this.adapter.testStatesEmitter.fire(c.getStartEvent());
this.adapter.testStatesEmitter.fire(c.getSkippedEvent());
}
});
}
}
execParams.push('--reporter');
execParams.push('xml');
Expand Down Expand Up @@ -166,7 +168,7 @@ export class C2TestSuiteInfo implements TestSuiteInfo {
const b = data.buffer.indexOf('<TestCase');
if (b == -1) return;

const testCaseTagRe = '<TestCase(?:\\s+|\\s+[^>]+)?>';
const testCaseTagRe = '<TestCase(?:\\s+[^\n]+)?>';
const m = data.buffer.match(testCaseTagRe);
if (m == null || m.length != 1) return;
let name: string = '';
Expand Down Expand Up @@ -266,10 +268,8 @@ export class C2TestSuiteInfo implements TestSuiteInfo {
}

reloadChildren(): Promise<void> {
return promisify(fs.exists)(this.execPath).then((exists: boolean) => {
if (!exists)
throw Error('reloadSuiteChildren: Should exists: ' + this.execPath);

return c2fs.existsAsync(this.execPath).then((exists: boolean) => {
if (!exists) throw new Error('Path not exists: ' + this.execPath);
return c2fs
.spawnAsync(
this.execPath,
Expand Down
Loading

0 comments on commit 9be32c6

Please sign in to comment.