Skip to content

Commit

Permalink
Merge pull request #27 from matepek/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
matepek authored Nov 25, 2018
2 parents a06a4c8 + f1ca84c commit 54879a2
Show file tree
Hide file tree
Showing 13 changed files with 358 additions and 203 deletions.
4 changes: 4 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,9 @@ If applicable, add screenshots to help explain your problem.
- Catch2 Version
- OS Type and Version

**Log**
Attach log. (optional, Set: `catch2TestExplorer.logfile` and reproduce the bug.)
_Warning_: Log probably contains file and test names too. Consider security conserns before attach!

**Additional context**
Add any other context about the problem here.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [2.2.1]

Stability improvements.

### Fixed

- relative patter/path outside of workspace didn't work
- tests are added/removed if change detected under running tests

## [2.2.0] - 2018-11-25

Performance and stability improvements. Improved logging.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Examples:

```json
"catch2TestExplorer.executables": {
"name": "${relName} (${relDirname}/)",
"name": "${relPath} (${relDirpath}/)",
"pattern": "{build,Build,BUILD,out,Out,OUT}/**/*{test,Test,TEST}*",
"cwd": "${absDirpath}",
"env": {
Expand Down Expand Up @@ -150,4 +150,4 @@ Any contribution is welcome.

- Create a pull request.
- Report a bug.
- Tell me about requested features.
- Tell me about your requested features.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@
],
"default": [
{
"name": "${relPath} (${relDirpath}/)",
"path": "{build,Build,BUILD,out,Out,OUT}/**/*{test,Test,TEST}*",
"name": "${filename} (${relDirpath}/)",
"pattern": "{build,Build,BUILD,out,Out,OUT}/**/*{test,Test,TEST}*",
"cwd": "${absDirpath}",
"env": {
"C2TESTEXECUTABLEPATH": "${absPath}"
Expand Down
3 changes: 2 additions & 1 deletion src/C2AllTestSuiteInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {TaskPool} from './TaskPool';
export class C2AllTestSuiteInfo implements TestSuiteInfo, vscode.Disposable {
readonly type: 'suite' = 'suite';
readonly id: string;
readonly label: string = 'Catch2 Test Explorer (matepek)';
readonly label: string;
readonly children: C2TestSuiteInfo[] = [];
private readonly _executables: C2ExecutableInfo[] = [];
private _isDisposed = false;
Expand All @@ -40,6 +40,7 @@ export class C2AllTestSuiteInfo implements TestSuiteInfo, vscode.Disposable {
public execWatchTimeout: number,
public isNoThrow: boolean,
) {
this.label = workspaceFolder.name + ' - Catch2';
this.id = generateUniqueId();
}

Expand Down
2 changes: 1 addition & 1 deletion src/C2ExecutableInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class C2ExecutableInfo implements vscode.Disposable {

let fileUris: vscode.Uri[] = [];

if (!isAbsolute || isPartOfWs) {
if (isPartOfWs) {
let relativePattern: vscode.RelativePattern;
if (isAbsolute)
relativePattern = new vscode.RelativePattern(
Expand Down
93 changes: 50 additions & 43 deletions src/C2TestAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {resolveVariables} from './Helpers';
import {QueueGraphNode} from './QueueGraph';

export class C2TestAdapter implements TestAdapter, vscode.Disposable {
private readonly _log: util.Log;
private readonly _testsEmitter =
new vscode.EventEmitter<TestLoadStartedEvent|TestLoadFinishedEvent>();
private readonly _testStatesEmitter =
Expand All @@ -34,10 +35,11 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
private _allTests: C2AllTestSuiteInfo;
private readonly _disposables: vscode.Disposable[] = [];

constructor(
private readonly _workspaceFolder: vscode.WorkspaceFolder,
private readonly _log: util.Log,
) {
constructor(private readonly _workspaceFolder: vscode.WorkspaceFolder) {
this._log = new util.Log(
'catch2TestExplorer', this._workspaceFolder, 'Catch2 Test Explorer');
this._disposables.push(this._log);

this._log.info(
'info: ' + inspect([
process.platform, process.version, process.versions, vscode.version
Expand Down Expand Up @@ -168,7 +170,7 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
run(tests: string[]): Promise<void> {
if (this._allTasks.size > 0) {
this._log.info(__filename + 'run is busy');
throw 'Catch2 is busy. Try it again a bit later.';
// throw 'Catch2 is busy. Try it again a bit later.';
}

return this._allTasks.then(() => {
Expand All @@ -183,11 +185,18 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
throw 'Catch2 is busy. Try it again a bit later.';
}

this._log.info('Debug...');
this._log.info('Debugging');

console.assert(tests.length === 1);
if (tests.length !== 1) {
this._log.error('unsupported test count: ' + inspect(tests));
throw Error('Unsupported input. Contact');
}
const info = this._allTests.findChildById(tests[0]);
console.assert(info !== undefined);
if (info === undefined) {
this._log.error(
'Not existing id: ' + inspect([tests, this._allTasks], true, 3));
throw Error('Not existing test id');
}

if (!(info instanceof C2TestInfo)) {
this._log.info(__filename + ' !(info instanceof C2TestInfo)');
Expand All @@ -202,24 +211,24 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
const debug: vscode.DebugConfiguration = {
name: 'Catch2: ' + testInfo.label,
request: 'launch',
type: ''
type: 'cppdbg',
};

const config = this._getConfiguration();
const template = this._getDebugConfigurationTemplate(config);
let resolveDebugVariables: [string, any][] = this._variableToValue;

const args = [testInfo.getEscapedTestName(), '--reporter', 'console'];
if (this._getDebugBreakOnFailure(config)) args.push('--break');

resolveDebugVariables = resolveDebugVariables.concat([
['${label}', testInfo.label],
['${exec}', testInfo.parent.execPath],
['${args}', args],
['${cwd}', testInfo.parent.execOptions.cwd!],
['${envObj}', testInfo.parent.execOptions.env!],
]);

if (template !== null) {
const resolveDebugVariables: [string, any][] = [
...this._variableToValue,
['${label}', testInfo.label],
['${exec}', testInfo.parent.execPath],
['${args}', args],
['${cwd}', testInfo.parent.execOptions.cwd!],
['${envObj}', testInfo.parent.execOptions.env!],
];
for (const prop in template) {
const val = template[prop];
if (val !== undefined && val !== null) {
Expand Down Expand Up @@ -325,26 +334,6 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
return config.get<boolean>('defaultNoThrow', false);
}

private _getGlobalAndDefaultEnvironmentVariables(
config: vscode.WorkspaceConfiguration):
{[prop: string]: string|undefined} {
const processEnv = process.env;
const configEnv: {[prop: string]: any} = config.get('defaultEnv') || {};

const resultEnv = {...processEnv};

for (const prop in configEnv) {
const val = configEnv[prop];
if (val === undefined || val === null) {
delete resultEnv.prop;
} else {
resultEnv[prop] = resolveVariables(String(val), this._variableToValue);
}
}

return resultEnv;
}

private _getDefaultCwd(config: vscode.WorkspaceConfiguration): string {
const dirname = this._workspaceFolder.uri.fsPath;
const cwd = resolveVariables(
Expand All @@ -370,8 +359,27 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
return config.get<number>('defaultWatchTimeoutSec', 10) * 1000;
}

private _getGlobalAndDefaultEnvironmentVariables(
config: vscode.WorkspaceConfiguration):
{[prop: string]: string|undefined} {
const processEnv = process.env;
const configEnv: {[prop: string]: any} = config.get('defaultEnv') || {};

const resultEnv = {...processEnv};

for (const prop in configEnv) {
const val = configEnv[prop];
if (val === undefined || val === null) {
delete resultEnv.prop;
} else {
resultEnv[prop] = resolveVariables(String(val), this._variableToValue);
}
}

return resultEnv;
}

private _getGlobalAndCurrentEnvironmentVariables(
config: vscode.WorkspaceConfiguration,
configEnv: {[prop: string]: any}): {[prop: string]: any} {
const processEnv = process.env;
const resultEnv = {...processEnv};
Expand Down Expand Up @@ -404,22 +412,21 @@ export class C2TestAdapter implements TestAdapter, vscode.Disposable {
{[prop: string]: any}[] = config.get('executables');

const createFromObject = (obj: {[prop: string]: any}): C2ExecutableInfo => {
const name: string =
obj.hasOwnProperty('name') ? obj.name : '${relName} (${relDirname}/)';
const name: string = obj.hasOwnProperty('name') ? obj.name : '${relPath}';

let pattern: string = '';
if (obj.hasOwnProperty('pattern') && typeof obj.pattern == 'string')
pattern = obj.pattern;
else if (obj.hasOwnProperty('path') && typeof obj.path == 'string')
pattern = obj.path;
else
throw Error('Error: pattern or path property is required.');
throw Error('Error: pattern property is required.');

const cwd: string =
obj.hasOwnProperty('cwd') ? obj.cwd : globalWorkingDirectory;

const env: {[prop: string]: any} = obj.hasOwnProperty('env') ?
this._getGlobalAndCurrentEnvironmentVariables(config, obj.env) :
this._getGlobalAndCurrentEnvironmentVariables(obj.env) :
this._getGlobalAndDefaultEnvironmentVariables(config);

return new C2ExecutableInfo(allTests, name, pattern, cwd, env);
Expand Down
100 changes: 54 additions & 46 deletions src/C2TestSuiteInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export class C2TestSuiteInfo implements TestSuiteInfo {
{type: 'suite', suite: this, state: 'running'});

const execParams: string[] = [];
if (childrenToRun != 'all') {
if (childrenToRun !== 'all') {
let testNames: string[] = [];
for (let i = 0; i < childrenToRun.length; i++) {
const c = childrenToRun[i];
Expand Down Expand Up @@ -160,13 +160,15 @@ export class C2TestSuiteInfo implements TestSuiteInfo {
beforeFirstTestCase: boolean = true;
rngSeed: number|undefined = undefined;
unporessedTestCases: string[] = [];
processedTestCases: C2TestInfo[] = [];
}
();

const testCaseTagRe = /<TestCase(?:\s+[^\n\r]+)?>/;

const processChunk = (chunk: string) => {
data.buffer = data.buffer + chunk;
let invariant = 99999;
const testCaseTagRe = /<TestCase(?:\s+[^\n\r]+)?>/;
do {
if (!data.inTestCase) {
const b = data.buffer.indexOf('<TestCase');
Expand Down Expand Up @@ -202,6 +204,7 @@ export class C2TestSuiteInfo implements TestSuiteInfo {
});

if (data.currentChild !== undefined) {
data.processedTestCases.push(data.currentChild);
const ev = data.currentChild.getStartEvent();
this.allTests.testStatesEmitter.fire(ev);
} else {
Expand Down Expand Up @@ -231,50 +234,6 @@ export class C2TestSuiteInfo implements TestSuiteInfo {
this.allTests.log.info(
'<TestCase> found without TestInfo: ' + inspect(this, true, 1) +
'; ' + testCaseXml);
if (data.unporessedTestCases.length == 0) {
this.allTests
.sendLoadEvents(() => {
return this.reloadChildren().catch(e => {
this.allTests.log.error(
'reload after new test found: ' + inspect(e));
// Suite possibly deleted: It is a dead suite.
});
})
.then(() => {
const events: TestEvent[] = [];

for (let i = 0; i < data.unporessedTestCases.length; i++) {
const testCaseXml = data.unporessedTestCases[i];

const m = testCaseXml.match(testCaseTagRe);
if (m == null || m.length != 1) break;

let name: string|undefined = undefined;
new xml2js.Parser({explicitArray: true})
.parseString(
m[0] + '</TestCase>', (err: any, result: any) => {
if (err) {
this.allTests.log.error(err.toString());
} else {
name = result.TestCase.$.name;
}
});
if (name === undefined) break;

const currentChild =
this.children.find((v: C2TestInfo) => {
return v.testNameTrimmed == name;
});
if (currentChild === undefined) break;

const ev = currentChild.parseAndProcessTestCase(
testCaseXml, data.rngSeed);
events.push(currentChild.getStartEvent());
events.push(ev);
}
this._sendTestStateEventsWithParent(events);
});
}
data.unporessedTestCases.push(testCaseXml);
}

Expand Down Expand Up @@ -309,6 +268,55 @@ export class C2TestSuiteInfo implements TestSuiteInfo {
taskPool.release();
this.allTests.testStatesEmitter.fire(
{type: 'suite', suite: this, state: 'completed'});

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

if (data.unporessedTestCases.length > 0 || isTestRemoved) {
this.allTests
.sendLoadEvents(() => {
return this.reloadChildren().catch(e => {
this.allTests.log.error(
'reloading-error after new test found: ' + inspect(e));
// Suite possibly deleted: It is a dead suite.
});
})
.then(() => {
const events: TestEvent[] = [];

for (let i = 0; i < data.unporessedTestCases.length; i++) {
const testCaseXml = data.unporessedTestCases[i];

const m = testCaseXml.match(testCaseTagRe);
if (m == null || m.length != 1) break;

let name: string|undefined = undefined;
new xml2js.Parser({explicitArray: true})
.parseString(
m[0] + '</TestCase>', (err: any, result: any) => {
if (err) {
this.allTests.log.error(err.toString());
} else {
name = result.TestCase.$.name;
}
});
if (name === undefined) break;

const currentChild = this.children.find((v: C2TestInfo) => {
return v.testNameTrimmed == name;
});
if (currentChild === undefined) break;

const ev = currentChild.parseAndProcessTestCase(
testCaseXml, data.rngSeed);
events.push(currentChild.getStartEvent());
events.push(ev);
}
events.length && this._sendTestStateEventsWithParent(events);
});
}
};
return p.then(
() => {
Expand Down
Loading

0 comments on commit 54879a2

Please sign in to comment.