Skip to content

Commit

Permalink
Merge pull request #50 from matepek/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
matepek authored Jan 5, 2019
2 parents a41c702 + b128754 commit 8e13f0f
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 152 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.3.10]

Performance and stability impovements.

## [2.3.9] - 2019-01-03

### Fixed
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ and [Google Test](https://github.com/google/googletest) tests using the
| `catch2TestExplorer.debugBreakOnFailure` | Debugger breaks on failure while debugging the test. Catch2: --break; Google Test: --gtest_break_on_failure; |
| `catch2TestExplorer.defaultNoThrow` | Skips all assertions that test that an exception is thrown, e.g. REQUIRE_THROWS. This is a Catch2 parameter: --nothrow |
| `catch2TestExplorer.defaultRngSeed` | Catch2: `--rng-seed <number> or "time"`; Google Test: `--gtest_random_seed=<number>`; |
| `catch2TestExplorer.defaultWatchTimeoutSec` | Test executables are being watched. In case of one compiles too much this variable can help with it. Unit: second. |
| `catch2TestExplorer.defaultRunningTimeoutSec` | Test executable is running in a process. In case of an inifinite loop, it will run forever, unless this parameter is set. |
| `catch2TestExplorer.workerMaxNumber` | The variable maximize the number of the parallel test execution. |
| `catch2TestExplorer.defaultWatchTimeoutSec` | Test executables are being watched. In case of one compiles too much this variable can help with it. Unit: second. It applies instantly. |
| `catch2TestExplorer.defaultRunningTimeoutSec` | Test executable is running in a process. In case of an inifinite loop, it will run forever, unless this parameter is set. It applies instantly. |
| `catch2TestExplorer.workerMaxNumber` | The variable maximize the number of the parallel test execution. It applies instantly. |
| `testExplorer.errorDecoration` | Show error messages from test failures as decorations in the editor. [Details](https://github.com/hbenl/vscode-test-explorer#configuration) |
| `testExplorer.gutterDecoration` | Show the state of each test in the editor using Gutter Decorations. [Details](https://github.com/hbenl/vscode-test-explorer#configuration) |
| `testExplorer.codeLens` | Show a CodeLens above each test or suite for running or debugging the tests. [Details](https://github.com/hbenl/vscode-test-explorer#configuration) |
Expand Down Expand Up @@ -83,7 +83,7 @@ Otherwise it only can point to an executable (No _search-pattern_!).
"pattern": "{build,Build,BUILD,out,Out,OUT}/**/*{test,Test,TEST}*",
"cwd": "${absDirpath}",
"env": {
"ExampleENV1": "You can use variables here too, like ${absName}"
"ExampleENV1": "You can use variables here too, like ${absPath}"
}
}
```
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.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"icon": "resources/icon.png",
"author": "Mate Pek",
"publisher": "matepek",
"version": "2.3.9",
"version": "2.3.10",
"license": "Unlicense",
"homepage": "https://github.com/matepek/vscode-catch2-test-adapter",
"repository": {
Expand Down
10 changes: 5 additions & 5 deletions src/GoogleTestSuiteInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export class GoogleTestSuiteInfo extends TestSuiteInfoBase {
test: data.currentChild!,
state: 'failed',
};
if (runInfo.timeout !== undefined) {
if (runInfo.timeout != undefined) {
ev.message = this._getTimeoutMessage(runInfo.timeout);
} else {
ev.message = 'Fatal error: (Wrong Google Test output.)\nError: ' + inspect(codeOrReason) + '\n';
Expand All @@ -277,10 +277,10 @@ export class GoogleTestSuiteInfo extends TestSuiteInfoBase {
}
}

const isTestRemoved = (runInfo.childrenToRun === 'all' &&
this.children.filter(c => !c.skipped).length >
data.processedTestCases.length) ||
(runInfo.childrenToRun !== 'all' && data.processedTestCases.length == 0);
const isTestRemoved = (runInfo.timeout == undefined)
&& ((runInfo.childrenToRun === 'all'
&& this.children.filter(c => !c.skipped).length > data.processedTestCases.length)
|| (runInfo.childrenToRun !== 'all' && data.processedTestCases.length == 0));

if (data.unprocessedTestCases.length > 0 || isTestRemoved) {
this.allTests
Expand Down
64 changes: 0 additions & 64 deletions src/QueueGraph.ts

This file was deleted.

31 changes: 23 additions & 8 deletions src/RootTestSuiteInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { TestExecutableInfo } from './TestExecutableInfo'
import { TestInfoBase } from './TestInfoBase';
import { TestSuiteInfoBase } from './TestSuiteInfoBase';
import { generateUniqueId } from './IdGenerator';
import { QueueGraphNode } from './QueueGraph';
import { TaskQueue } from './TaskQueue';
import { TaskPool } from './TaskPool';

export class RootTestSuiteInfo implements TestSuiteInfo, vscode.Disposable {
Expand All @@ -21,9 +21,10 @@ export class RootTestSuiteInfo implements TestSuiteInfo, vscode.Disposable {
readonly children: TestSuiteInfoBase[] = [];
private readonly _executables: TestExecutableInfo[] = [];
private _isDisposed = false;
private readonly _taskPool: TaskPool;

constructor(
private readonly _allTasks: QueueGraphNode,
private readonly _allTasks: TaskQueue,
public readonly log: util.Log,
public readonly workspaceFolder: vscode.WorkspaceFolder,
private readonly _loadFinishedEmitter: vscode.EventEmitter<string | undefined>,
Expand All @@ -32,20 +33,36 @@ export class RootTestSuiteInfo implements TestSuiteInfo, vscode.Disposable {
public readonly testStatesEmitter:
vscode.EventEmitter<TestRunStartedEvent | TestRunFinishedEvent |
TestSuiteEvent | TestEvent>,
public readonly autorunEmitter: vscode.EventEmitter<void>,
public readonly variableToValue: [string, string][],
public isEnabledSourceDecoration: boolean,
public rngSeed: string | number | null,
public execWatchTimeout: number,
public execRunningTimeout: null | number,
private _execRunningTimeout: null | number,
public isNoThrow: boolean,
workerMaxNumber: number,
) {
this.label = workspaceFolder.name + ' (Catch2 and Google Test Explorer)';
this.id = generateUniqueId();
this._taskPool = new TaskPool(workerMaxNumber);
}

set workerMaxNumber(workerMaxNumber: number) {
this._taskPool.maxTaskCount = workerMaxNumber;
}

get execRunningTimeout() { return this._execRunningTimeout; }

set execRunningTimeout(value: null | number) {
this._execRunningTimeout = value;
this._execRunningTimeoutChangeEmitter.fire();
}

private readonly _execRunningTimeoutChangeEmitter = new vscode.EventEmitter<void>();
readonly onDidExecRunningTimeoutChanged = this._execRunningTimeoutChangeEmitter.event;

dispose() {
this._isDisposed = true;
this._execRunningTimeoutChangeEmitter.dispose();
for (let i = 0; i < this._executables.length; i++) {
this._executables[i].dispose();
}
Expand Down Expand Up @@ -144,11 +161,9 @@ export class RootTestSuiteInfo implements TestSuiteInfo, vscode.Disposable {
}
}

run(tests: string[], workerMaxNumber: number): Promise<void> {
run(tests: string[]): Promise<void> {
this.testStatesEmitter.fire({ type: 'started', tests: tests });

const taskPool = new TaskPool(workerMaxNumber);

// everybody should remove what they use from it.
// and put their children into if they are in it
const testSet = new Set(tests);
Expand All @@ -162,7 +177,7 @@ export class RootTestSuiteInfo implements TestSuiteInfo, vscode.Disposable {
const ps: Promise<void>[] = [];
for (let i = 0; i < this.children.length; i++) {
const child = this.children[i];
ps.push(child.run(testSet, taskPool));
ps.push(child.run(testSet, this._taskPool));
}

if (testSet.size > 0) {
Expand Down
60 changes: 49 additions & 11 deletions src/TaskPool.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,57 @@
export class TaskPool {
/**
*
* @param availableSlot The available slot number. If -1 (negative) means no limit, acquire will always return true.
* @param maxTaskCount Has to be bigger than 0 or `undefined`.
*/
constructor(private availableSlot: number) {}
constructor(private _maxTaskCount: number | undefined) {
if (_maxTaskCount != undefined && _maxTaskCount < 1) throw Error('invalid argument');
}

get maxTaskCount(): number | undefined {
return this._maxTaskCount;
}

set maxTaskCount(maxTaskCount: number | undefined) {
if (maxTaskCount != undefined && maxTaskCount < 1) throw Error('invalid argument');
this._maxTaskCount = maxTaskCount;

while (this._waitingTasks.length > 0 && this._acquire())
this._waitingTasks.pop()!();
}

acquire(): boolean {
if (this.availableSlot < 0) return true;
if (this.availableSlot == 0) return false;
this.availableSlot -= 1;
return true;
scheduleTask<TResult>(task: () => TResult | PromiseLike<TResult>): Promise<TResult> {
return new Promise<void>(resolve => {
if (this._acquire())
resolve();
else
this._waitingTasks.unshift(resolve);
}).then(task)
.then(
(v: TResult) => {
this._release();
return v;
},
(reason?: any) => {
this._release();
throw reason;
});
}

release(): void {
if (this.availableSlot < 0) return;
this.availableSlot += 1;
private _runningTaskCount: number = 0;
private readonly _waitingTasks: (() => void)[] = [];

private _acquire(): boolean {
if (this._maxTaskCount === undefined || this._runningTaskCount < this._maxTaskCount) {
this._runningTaskCount += 1;
return true;
} else {
return false;
}
}

private _release(): void {
this._runningTaskCount -= 1;

while (this._waitingTasks.length > 0 && this._acquire())
this._waitingTasks.pop()!();
}
}
52 changes: 52 additions & 0 deletions src/TaskQueue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//-----------------------------------------------------------------------------
// 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.

export class TaskQueue {
constructor(depends: Iterable<TaskQueue> = [],
public readonly name?: string) {
this._depends = [...depends];
// TODO check circular dependency
}

empty(): boolean {
return this._count == 0;
}

get size(): number {
return this._count;
}

get length(): number {
return this._count;
}

then<TResult1>(
task: (() => TResult1 | PromiseLike<TResult1>)): Promise<TResult1> {
this._count++;

const previous = this._queue;

const current = Promise.all(this._depends.map(v => v._queue))
.then(() => {
return previous.then(task);
});

const decr = () => { this._count--; };

this._queue = current.then(decr, decr);

return current;
}

dependsOn(depends: Iterable<TaskQueue>): void {
for (const dep of depends) {
this._depends.push(dep);
}
// TODO check circular dependency
}

private _count: number = 0;
private _queue: Promise<void> = Promise.resolve();
private readonly _depends: Array<TaskQueue>;
}
Loading

0 comments on commit 8e13f0f

Please sign in to comment.