From 22ef89564d48995c4a4c8cac7b75a9d471b1f8f7 Mon Sep 17 00:00:00 2001 From: Siza Date: Fri, 6 Aug 2021 14:23:18 +1200 Subject: [PATCH 01/18] Add CppUTest support --- package.json | 3 +- src/AdvancedExecutableInterface.ts | 1 + src/Configurations.ts | 2 + src/ExecutableConfig.ts | 2 + src/RunnableFactory.ts | 29 ++ src/Spawner.ts | 2 +- src/framework/CppUTestRunnable.ts | 442 ++++++++++++++++++++++++ src/framework/CppUTestTest.ts | 111 ++++++ test/ExecutableConfig.test.ts | 1 + test/RunnableFactory.test.ts | 2 + test/framework/CppUTestRunnable.test.ts | 160 +++++++++ test/framework/CppUTestTest.test.ts | 109 ++++++ 12 files changed, 862 insertions(+), 2 deletions(-) create mode 100644 src/framework/CppUTestRunnable.ts create mode 100644 src/framework/CppUTestTest.ts create mode 100644 test/framework/CppUTestRunnable.test.ts create mode 100644 test/framework/CppUTestTest.test.ts diff --git a/package.json b/package.json index e6f33a0c..3950b3f4 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,8 @@ "tslib": "^2.2.0", "vscode-test-adapter-api": "^1.9.0", "vscode-test-adapter-util": "^0.7.1", - "xml2js": "^0.4.23" + "xml2js": "^0.4.23", + "junit-report-merger": "^2.2.3" }, "devDependencies": { "@sentry/node": "^6.5.0", diff --git a/src/AdvancedExecutableInterface.ts b/src/AdvancedExecutableInterface.ts index c965fa97..5191c312 100644 --- a/src/AdvancedExecutableInterface.ts +++ b/src/AdvancedExecutableInterface.ts @@ -21,6 +21,7 @@ export interface AdvancedExecutable { catch2?: FrameworkSpecific; gtest?: FrameworkSpecific; doctest?: FrameworkSpecific; + cpputest?: FrameworkSpecific; gbenchmark?: FrameworkSpecific; testGrouping?: TestGrouping; executionWrapper?: ExecutionWrapper; diff --git a/src/Configurations.ts b/src/Configurations.ts index 56718d5f..15a54a1d 100644 --- a/src/Configurations.ts +++ b/src/Configurations.ts @@ -406,6 +406,7 @@ export class Configurations { {}, {}, {}, + {}, ); }; @@ -538,6 +539,7 @@ export class Configurations { this._getFrameworkSpecificSettings(defaultTestGrouping, obj['catch2']), this._getFrameworkSpecificSettings(defaultTestGrouping, obj['gtest']), this._getFrameworkSpecificSettings(defaultTestGrouping, obj['doctest']), + this._getFrameworkSpecificSettings(defaultTestGrouping, obj['cpputest']), this._getFrameworkSpecificSettings(defaultTestGrouping, obj['gbenchmark']), ); }; diff --git a/src/ExecutableConfig.ts b/src/ExecutableConfig.ts index 81416122..d9a8f560 100644 --- a/src/ExecutableConfig.ts +++ b/src/ExecutableConfig.ts @@ -42,6 +42,7 @@ export class ExecutableConfig implements vscode.Disposable { private readonly _catch2: FrameworkSpecific, private readonly _gtest: FrameworkSpecific, private readonly _doctest: FrameworkSpecific, + private readonly _cpputest: FrameworkSpecific, private readonly _gbenchmark: FrameworkSpecific, ) { const createUriSymbol: unique symbol = Symbol('createUri'); @@ -388,6 +389,7 @@ export class ExecutableConfig implements vscode.Disposable { this._catch2, this._gtest, this._doctest, + this._cpputest, this._gbenchmark, this._parallelizationLimit, this._markAsSkipped === true, diff --git a/src/RunnableFactory.ts b/src/RunnableFactory.ts index 54ba2cf4..5574d314 100644 --- a/src/RunnableFactory.ts +++ b/src/RunnableFactory.ts @@ -4,6 +4,7 @@ import { AbstractRunnable } from './AbstractRunnable'; import { Catch2Runnable } from './framework/Catch2Runnable'; import { GoogleTestRunnable } from './framework/GoogleTestRunnable'; import { DOCRunnable } from './framework/DOCRunnable'; +import { CppUTestRunnable } from './framework/CppUTestRunnable'; import { SharedVariables } from './SharedVariables'; import { FrameworkSpecific, RunTask } from './AdvancedExecutableInterface'; import { Version } from './Util'; @@ -24,6 +25,7 @@ export class RunnableFactory { private readonly _catch2: FrameworkSpecific, private readonly _gtest: FrameworkSpecific, private readonly _doctest: FrameworkSpecific, + private readonly _cpputest: FrameworkSpecific, private readonly _gbenchmark: FrameworkSpecific, private readonly _parallelizationLimit: number, private readonly _markAsSkipped: boolean, @@ -156,6 +158,33 @@ export class RunnableFactory { ); } } + { + if (this._cpputest.helpRegex) this._shared.log.info('Custom regex', 'cpputest', this._cpputest.helpRegex); + + const cpputest = runWithHelpRes.stdout.match( + this._cpputest.helpRegex ? new RegExp(this._cpputest.helpRegex, regexFlags) : /Thanks for using CppUTest/, + ); + if (cpputest) { + return new CppUTestRunnable( + this._shared, + this._rootSuite, + new RunnableProperties( + this._execName, + this._execDescription, + this._varToValue, + this._execPath, + this._execOptions, + this._cpputest, + this._parallelizationLimit, + this._markAsSkipped, + this._runTask, + this._spawner, + this._sourceFileMap, + ), + Promise.resolve(undefined), + ); + } + } { if (this._gbenchmark.helpRegex) diff --git a/src/Spawner.ts b/src/Spawner.ts index 14cabaae..8f3cf037 100644 --- a/src/Spawner.ts +++ b/src/Spawner.ts @@ -39,7 +39,7 @@ export class DefaultSpawner implements Spawner { Object.assign(ret, { process: command }); // for debugging - ret.pid = command.pid; + if (command.pid !== undefined) ret.pid = command.pid; command.stdout.on('data', function (data) { ret.stdout += data; diff --git a/src/framework/CppUTestRunnable.ts b/src/framework/CppUTestRunnable.ts new file mode 100644 index 00000000..a96e037d --- /dev/null +++ b/src/framework/CppUTestRunnable.ts @@ -0,0 +1,442 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as glob from 'glob'; +import { inspect, promisify } from 'util'; +import { mergeFiles } from 'junit-report-merger'; +import { Suite } from '../Suite'; +import { AbstractRunnable, RunnableReloadResult } from '../AbstractRunnable'; +import { CppUTestTest } from './CppUTestTest'; +import { Parser } from 'xml2js'; +import { RunnableProperties } from '../RunnableProperties'; +import { SharedVariables } from '../SharedVariables'; +import { RunningRunnable, ProcessResult } from '../RunningRunnable'; +import { AbstractTest, AbstractTestEvent } from '../AbstractTest'; +import { CancellationFlag, Version } from '../Util'; +import { TestGrouping } from '../TestGroupingInterface'; +import { RootSuite } from '../RootSuite'; + +export class CppUTestRunnable extends AbstractRunnable { + public constructor( + shared: SharedVariables, + rootSuite: RootSuite, + execInfo: RunnableProperties, + // private readonly _argumentPrefix: string, + version: Promise, + ) { + super(shared, rootSuite, execInfo, 'CppUTest', version); + } + + private getTestGrouping(): TestGrouping { + if (this.properties.testGrouping) { + return this.properties.testGrouping; + } else { + const grouping = { groupByExecutable: this._getGroupByExecutable() }; + // grouping.groupByExecutable.groupByTags = { tags: [], tagFormat: '${tag}' }; + return grouping; + } + } + + private async _reloadFromXml(xmlStr: string, cancellationFlag: CancellationFlag): Promise { + const testGrouping = this.getTestGrouping(); + + interface XmlObject { + [prop: string]: any; //eslint-disable-line + } + + let xml: XmlObject = {}; + + new Parser({ explicitArray: true }).parseString(xmlStr, (err: Error, result: Record) => { + if (err) { + throw err; + } else { + xml = result; + } + }); + + const reloadResult = new RunnableReloadResult(); + + for (let i = 0; i < xml.testsuites.testsuite.length; ++i) { + const suiteName = xml.testsuites.testsuite[i].$.name; + + for (let j = 0; j < xml.testsuites.testsuite[i].testcase.length; j++) { + if (cancellationFlag.isCancellationRequested) return reloadResult; + + const testCase = xml.testsuites.testsuite[i].testcase[j]; + const testName = testCase.$.name.startsWith('DISABLED_') ? testCase.$.name.substr(9) : testCase.$.name; + const testNameAsId = suiteName + '.' + testCase.$.name; + + const file = testCase.$.file ? await this._resolveSourceFilePath(testCase.$.file) : undefined; + const line = testCase.$.line ? testCase.$.line - 1 : undefined; + + reloadResult.add( + ...(await this._createSubtreeAndAddTest( + testGrouping, + testNameAsId, + testName, + file, + [suiteName], + (parent: Suite) => new CppUTestTest(this._shared, this, parent, testNameAsId, testName, file, line), + (old: AbstractTest) => (old as CppUTestTest).update(testNameAsId, file, line), + )), + ); + } + } + + return reloadResult; + } + + private async _reloadFromString( + stdOutStr: string, + cancellationFlag: CancellationFlag, + ): Promise { + const testGrouping = this.getTestGrouping(); + const lines = stdOutStr.split(' '); + // const testGroupList = [...new Set(lines.map(gs => gs.split(".")[0]))]; + + const reloadResult = new RunnableReloadResult(); + + for (let i = 0; i < lines.length; i++) { + if (cancellationFlag.isCancellationRequested) return reloadResult; + const suiteName = lines[i].split('.')[0]; + const testName = lines[i].split('.')[1]; + const testNameAsId = suiteName + '.' + testName; + + reloadResult.add( + ...(await this._createSubtreeAndAddTest( + testGrouping, + testNameAsId, + testName, + undefined, + [suiteName], + (parent: Suite) => new CppUTestTest(this._shared, this, parent, testNameAsId, testName, undefined, undefined), + (old: AbstractTest) => (old as CppUTestTest).update(testNameAsId, undefined, undefined), + )), + ); + } + return reloadResult; + } + + protected async _reloadChildren(cancellationFlag: CancellationFlag): Promise { + const cacheFile = this.properties.path + '.TestMate.testListCache.xml'; + + if (this._shared.enabledTestListCaching) { + try { + const cacheStat = await promisify(fs.stat)(cacheFile); + const execStat = await promisify(fs.stat)(this.properties.path); + + if (cacheStat.size > 0 && cacheStat.mtime > execStat.mtime) { + this._shared.log.info('loading from cache: ', cacheFile); + const xmlStr = await promisify(fs.readFile)(cacheFile, 'utf8'); + + return await this._reloadFromXml(xmlStr, cancellationFlag); + } + } catch (e) { + this._shared.log.info('coudnt use cache', e); + } + } + + const args = this.properties.prependTestListingArgs.concat(['-ln']); + + this._shared.log.info('discovering tests', this.properties.path, args, this.properties.options.cwd); + const cppUTestListOutput = await this.properties.spawner.spawnAsync( + this.properties.path, + args, + this.properties.options, + 30000, + ); + + if (cppUTestListOutput.stderr && !this.properties.ignoreTestEnumerationStdErr) { + this._shared.log.warn('reloadChildren -> cppUTestListOutput.stderr: ', cppUTestListOutput); + return await this._createAndAddUnexpectedStdError(cppUTestListOutput.stdout, cppUTestListOutput.stderr); + } + + if (cppUTestListOutput.stdout.length === 0) { + this._shared.log.debug(cppUTestListOutput); + throw Error('stoud is empty'); + } + + const result = this._reloadFromString(cppUTestListOutput.stdout, cancellationFlag); + + if (this._shared.enabledTestListCaching) { + //Generate xml files + const args = this.properties.prependTestListingArgs.concat(['-ojunit']); + this._shared.log.info('create cpputest xmls', this.properties.path, args, this.properties.options.cwd); + await this.properties.spawner.spawnAsync(this.properties.path, args, this.properties.options, 30000); + try { + await mergeFiles(cacheFile, [path.dirname(this.properties.path) + '/*.xml']); + this._shared.log.info('cache xml written: ', cacheFile); + //Delete xml files + const currentFolder = path.dirname(this.properties.path); + glob(currentFolder + '/cpputest_*.xml', { cwd: currentFolder }, (err, files) => { + if (err) { + this._shared.log.debug('error finding xml files: ', currentFolder, err); + } + + for (const file of files) { + try { + fs.unlinkSync(file); + } catch (err) { + this._shared.log.warn('cache file could not delete: ', file, err); + } + } + }); + } catch (err) { + this._shared.log.warn('combine xml cache file could not create: ', cacheFile, err); + } + } + return result; + } + + protected _getRunParamsInner(childrenToRun: readonly Readonly[]): string[] { + // TODO Add multiple options + // return ['-c', '-v']; + + const execParams: string[] = []; + + childrenToRun.forEach(t => { + execParams.push(`TEST(${t.testNameAsId.split('.')[0]}, ${t.testNameAsId.split('.')[1]})`); + }); + + // execParams.push(testNames.join(' ')); + execParams.push('-c'); + execParams.push('-v'); + + return execParams; + } + + protected _getDebugParamsInner(childrenToRun: readonly Readonly[], breakOnFailure: boolean): string[] { + // TODO colouring 'debug.enableOutputColouring' + // TODO Add multiple options + // return ['-c', '-v']; + const execParams: string[] = []; + + childrenToRun.forEach(t => { + execParams.push(`TEST(${t.testNameAsId.split('.')[0]}, ${t.testNameAsId.split('.')[1]})`); + }); + + // execParams.push(testNames.join(' ')); + execParams.push('-c'); + execParams.push('-v'); + + return execParams; + } + + protected _handleProcess(testRunId: string, runInfo: RunningRunnable): Promise { + const data = new (class { + public stdoutAndErrBuffer = ''; // no reason to separate + public currentTestCaseNameFull: string | undefined = undefined; + public currentChild: AbstractTest | undefined = undefined; + public route: Suite[] = []; + public unprocessedTestCases: string[] = []; + public processedTestCases: AbstractTest[] = []; + })(); + + const testBeginRe = /^TEST\(((.+?)\,\s*(.+?))\)/m; + const rngSeed: number | undefined = typeof this._shared.rngSeed === 'number' ? this._shared.rngSeed : undefined; + + return new Promise(resolve => { + const chunks: string[] = []; + const processChunk = (chunk: string): void => { + chunks.push(chunk); + data.stdoutAndErrBuffer = data.stdoutAndErrBuffer + chunk; + let invariant = 99999; + do { + if (runInfo.cancellationToken.isCancellationRequested) return; + + if (data.currentTestCaseNameFull === undefined) { + const m = data.stdoutAndErrBuffer.match(testBeginRe); + if (m == null) return; + + data.currentTestCaseNameFull = m[2] + '.' + m[3]; + + const test = this._findTest(v => v.testNameAsId == data.currentTestCaseNameFull); + + if (test) { + const route = [...test.route()]; + this.sendMinimalEventsIfNeeded(testRunId, data.route, route); + data.route = route; + + data.currentChild = test; + this._shared.log.info('Test', data.currentChild.testNameAsId, 'has started.'); + this._shared.sendTestRunEvent(data.currentChild.getStartEvent(testRunId)); + } else { + this._shared.log.info('TestCase not found in children', data.currentTestCaseNameFull); + } + + data.stdoutAndErrBuffer = data.stdoutAndErrBuffer.substr(m.index!); + } else { + const testEndRe = / - \d+ ms$/m; + // const testEndRe = new RegExp( + // '(?!\\[ RUN \\])\\[..........\\] ' + data.currentTestCaseNameFull.replace('.', '\\.') + '.*$', + // 'm', + // ); + + const m = data.stdoutAndErrBuffer.match(testEndRe); + if (m == null) return; + + const testCase = data.stdoutAndErrBuffer.substring(0, m.index! + m[0].length); + + if (data.currentChild !== undefined) { + this._shared.log.info('Test ', data.currentChild.testNameAsId, 'has finished.'); + try { + const ev = data.currentChild.parseAndProcessTestCase( + testRunId, + testCase, + rngSeed, + runInfo.timeout, + undefined, + ); + + this._shared.sendTestRunEvent(ev); + + data.processedTestCases.push(data.currentChild); + } catch (e) { + this._shared.log.error('parsing and processing test', e, data); + + data.currentChild.lastRunEvent = { + testRunId, + type: 'test', + test: data.currentChild.id, + state: 'errored', + message: [ + 'šŸ˜± Unexpected error under parsing output !! Error: ' + inspect(e), + 'Consider opening an issue: https://github.com/matepek/vscode-catch2-test-adapter/issues/new/choose', + `Please attach the output of: "${runInfo.process.spawnfile} ${runInfo.process.spawnargs}"`, + '=== Output ===', + testCase, + '==============', + 'ā¬‡ stdoutAndErrBuffer:', + data.stdoutAndErrBuffer, + 'ā¬† stdoutAndErrBuffer', + 'ā¬‡ std::cout:', + runInfo.process.stdout, + 'ā¬† std::cout', + 'ā¬‡ std::cerr:', + runInfo.process.stderr, + 'ā¬† std::cerr', + ].join('\n'), + }; + + this._shared.sendTestRunEvent(data.currentChild.lastRunEvent); + } + } else { + this._shared.log.info('Test case found without TestInfo: ', this, '; ' + testCase); + data.unprocessedTestCases.push(testCase); + } + + data.currentTestCaseNameFull = undefined; + data.currentChild = undefined; + // do not clear data.route + data.stdoutAndErrBuffer = data.stdoutAndErrBuffer.substr(m.index! + m[0].length); + } + } while (data.stdoutAndErrBuffer.length > 0 && --invariant > 0); + if (invariant == 0) { + this._shared.log.error('invariant==0', this, runInfo, data, chunks); + resolve(ProcessResult.error('Possible infinite loop of this extension')); + runInfo.killProcess(); + } + }; + + runInfo.process.stdout.on('data', (chunk: Uint8Array) => processChunk(chunk.toLocaleString())); + runInfo.process.stderr.on('data', (chunk: Uint8Array) => processChunk(chunk.toLocaleString())); + + runInfo.process.once('close', (code: number | null, signal: string | null) => { + if (runInfo.cancellationToken.isCancellationRequested) { + resolve(ProcessResult.ok()); + } else { + if (code !== null && code !== undefined) resolve(ProcessResult.createFromErrorCode(code)); + else if (signal !== null && signal !== undefined) resolve(ProcessResult.createFromSignal(signal)); + else resolve(ProcessResult.error('unknown sfngvdlfkxdvgn')); + } + }); + }) + .catch((reason: Error) => { + // eslint-disable-next-line + if ((reason as any).code === undefined) this._shared.log.exceptionS(reason); + + return new ProcessResult(reason); + }) + .then((result: ProcessResult) => { + result.error && this._shared.log.info(result.error.toString(), result, runInfo, this, data); + + if (data.currentTestCaseNameFull !== undefined) { + if (data.currentChild !== undefined) { + this._shared.log.info('data.currentChild !== undefined: ', data); + + let ev: AbstractTestEvent; + + if (runInfo.cancellationToken.isCancellationRequested) { + ev = data.currentChild.getCancelledEvent(testRunId, data.stdoutAndErrBuffer); + } else if (runInfo.timeout !== null) { + ev = data.currentChild.getTimeoutEvent(testRunId, runInfo.timeout); + } else { + ev = data.currentChild.getFailedEventBase(testRunId); + + ev.message = 'šŸ˜± Unexpected error !!'; + + if (result.error) { + ev.state = 'errored'; + ev.message += '\n' + result.error.message; + } + + ev.message += data.stdoutAndErrBuffer ? `\n\n>>>${data.stdoutAndErrBuffer}<<<` : ''; + } + + data.currentChild.lastRunEvent = ev; + this._shared.sendTestRunEvent(ev); + } else { + this._shared.log.warn('data.inTestCase: ', data); + } + } + + this.sendMinimalEventsIfNeeded(testRunId, data.route, []); + data.route = []; + + const isTestRemoved = + runInfo.timeout === null && + !runInfo.cancellationToken.isCancellationRequested && + result.error === undefined && + data.processedTestCases.length < runInfo.childrenToRun.length; + + if (data.unprocessedTestCases.length > 0 || isTestRemoved) { + this.reloadTests(this._shared.taskPool, runInfo.cancellationToken).then( + () => { + // we have test results for the newly detected tests + // after reload we can set the results + const events: AbstractTestEvent[] = []; + + for (let i = 0; i < data.unprocessedTestCases.length; i++) { + const testCase = data.unprocessedTestCases[i]; + + const m = testCase.match(testBeginRe); + if (m == null) break; + + const testNameAsId = m[1]; + + const currentChild = this._findTest(v => v.compare(testNameAsId)); + + if (currentChild === undefined) break; + try { + const ev = currentChild.parseAndProcessTestCase( + testRunId, + testCase, + rngSeed, + runInfo.timeout, + undefined, + ); + events.push(ev); + } catch (e) { + this._shared.log.error('parsing and processing test', e, testCase); + } + } + events.length && this._shared.sendTestEvents(events); + }, + (reason: Error) => { + // Suite possibly deleted: It is a dead suite. + this._shared.log.error('reloading-error: ', reason); + }, + ); + } + }); + } +} diff --git a/src/framework/CppUTestTest.ts b/src/framework/CppUTestTest.ts new file mode 100644 index 00000000..2994d770 --- /dev/null +++ b/src/framework/CppUTestTest.ts @@ -0,0 +1,111 @@ +import { AbstractTest, AbstractTestEvent, SharedWithTest } from '../AbstractTest'; +import { Suite } from '../Suite'; +import { AbstractRunnable } from '../AbstractRunnable'; +import { TestEventBuilder } from '../TestEventBuilder'; + +export class CppUTestTest extends AbstractTest { + public constructor( + shared: SharedWithTest, + runnable: AbstractRunnable, + parent: Suite, + testNameAsId: string, + label: string, + file: string | undefined, + line: number | undefined, + ) { + super( + shared, + runnable, + parent, + testNameAsId, + label, + file, + line, + testNameAsId.startsWith('IGNORE_TEST'), + undefined, + [], + undefined, + undefined, + undefined, + ); + } + + private static _isSkipped(tags: string[], testNameAsId: string): boolean { + return tags.some((v: string) => v.startsWith('.') || v == 'hide' || v == '!hide') || testNameAsId.startsWith('./'); + } + + public update(testNameAsId: string | undefined, file: string | undefined, line: number | undefined): boolean { + const label = testNameAsId ? testNameAsId : this._label; + return this._updateBase( + label, + file, + line, + CppUTestTest._isSkipped(this._tags, this.testNameAsId), + this._tags, + this._testDescription, + undefined, + undefined, + this._staticEvent, + ); + } + + public compare(testNameAsId: string): boolean { + return this.testNameAsId === testNameAsId; + } + + public static readonly failureRe = /^((.+)[:\(]([0-9]+)\)?): ((Failure|EXPECT_CALL|error: )(.*))$/; + + public parseAndProcessTestCase( + testRunId: string, + output: string, + rngSeed: number | undefined, + timeout: number | null, + stderr: string | undefined, //eslint-disable-line + ): AbstractTestEvent { + if (timeout !== null) { + const ev = this.getTimeoutEvent(testRunId, timeout); + this.lastRunEvent = ev; + return ev; + } + + try { + const lines = output.split(/\r?\n/); + + // if (lines.length < 1) throw new Error('unexpected'); + // const testName = lines[i].match(/\((.*)\)/)[1].split(',')[1].trim(); + + const eventBuilder = new TestEventBuilder(this, testRunId); + + const runDuration = lines[lines.length - 1].match(/([0-9]+) ms/); + eventBuilder.setDurationMilisec(runDuration ? Number(runDuration[1]) : undefined); + + // const m = lines[i].match(endRe); + // if (m !== null) break; + + const isSkipped = lines[0].indexOf('IGNORE_TEST') != -1; + if (isSkipped) eventBuilder.skipped(); + if (lines.length === 1) eventBuilder.passed(); + else eventBuilder.failed(); + + if (!isSkipped && lines.length > 1) { + const match = lines[1].match(CppUTestTest.failureRe); + if (match !== null) { + const filePath = match[2].split('/').pop(); + const lineNumber = Number(match[3]) - 1; + eventBuilder.appendDecorator(filePath, lineNumber, [lines[3], lines[4]]); + } + } + + const event = eventBuilder.build(output.replace(/\): error: /g, '): error: \n')); + + return event; + } catch (e) { + this._shared.log.exceptionS(e, output); + + const ev = this.getFailedEventBase(testRunId); + ev.message = 'Unexpected error: ' + e.toString(); + + return e; + } + } +} diff --git a/test/ExecutableConfig.test.ts b/test/ExecutableConfig.test.ts index 4e60a341..403d2ea1 100644 --- a/test/ExecutableConfig.test.ts +++ b/test/ExecutableConfig.test.ts @@ -30,6 +30,7 @@ describe(path.basename(__filename), function () { {}, {}, {}, + {}, ); specify('_pathProcessor with posix name', async function () { diff --git a/test/RunnableFactory.test.ts b/test/RunnableFactory.test.ts index 390ca7a7..7d2b01bd 100644 --- a/test/RunnableFactory.test.ts +++ b/test/RunnableFactory.test.ts @@ -46,6 +46,7 @@ describe(path.basename(__filename), function () { {}, {}, {}, + {}, 1, false, {}, @@ -90,6 +91,7 @@ describe(path.basename(__filename), function () { {}, {}, {}, + {}, 1, false, {}, diff --git a/test/framework/CppUTestRunnable.test.ts b/test/framework/CppUTestRunnable.test.ts new file mode 100644 index 00000000..6babea90 --- /dev/null +++ b/test/framework/CppUTestRunnable.test.ts @@ -0,0 +1,160 @@ +import * as assert from 'assert'; +import * as pathlib from 'path'; +import { Imitation, SharedVariables } from '../Common'; +import { CppUTestRunnable } from '../../src/framework/CppUTestRunnable'; +import { RootSuite } from '../../src/RootSuite'; +import { RunnableProperties } from '../../src/RunnableProperties'; +// import { EOL } from 'os'; +import { DefaultSpawner } from '../../src/Spawner'; + +/// + +describe(pathlib.basename(__filename), function () { + const sharedVariables = new SharedVariables(); + + const runnableProperties = new RunnableProperties( + 'name', + undefined, + [ + { resolve: '${relDirpath}', rule: 'relDirpath' }, + { resolve: '${osPathSep}', rule: 'osPathSep' }, + ], + 'path', + {}, + {}, + 1, + false, + {}, + new DefaultSpawner(), + {}, + ); + + const createCppUTestRunnable = (): { runnable: CppUTestRunnable; root: RootSuite } => { + const root = new RootSuite(undefined, sharedVariables); + return { + root, + runnable: new CppUTestRunnable( + sharedVariables, + root, + runnableProperties, + // 'cpputest_', + Promise.resolve(undefined), + ), + }; + }; + + let imitation: Imitation; + + before(function () { + imitation = new Imitation(); + }); + + afterEach(function () { + imitation.resetToCallThrough(); + }); + + after(function () { + imitation.restore(); + }); + + context('Testing _reloadFromString', function () { + it('should reload ex.1', async function () { + const { root, runnable } = createCppUTestRunnable(); + assert.strictEqual(runnable.tests.size, 0); + + const testListOutput: string[] = [ + 'TeamCityOutputTest.TestNameEscaped_Fail', + 'TeamCityOutputTest.TestNameEscaped_Ignore', + 'TeamCityOutputTest.TestNameEscaped_End', + 'TeamCityOutputTest.TestNameEscaped_Start', + 'TeamCityOutputTest.TestGroupEscaped_End', + 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.MultipleTestsInSeparateProcessAreCountedProperly', + 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.CallToWaitPidFailedInSeparateProcessWorks', + 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.CallToWaitPidStopsAndReportsAnErrorAfter20TimesRetry', + 'SimpleMutexTest.LockUnlockTest', + 'SimpleMutexTest.CreateAndDestroy', + 'UtestShellPointerArrayTest.reverse', + ]; + const res = await runnable['_reloadFromString'](testListOutput.join(' '), { isCancellationRequested: false }); + + const tests = [...res.tests].sort((a, b) => a.testNameAsId.localeCompare(b.testNameAsId)); + + assert.strictEqual(tests.length, 11); + assert.strictEqual(tests[0].testNameAsId, 'SimpleMutexTest.CreateAndDestroy'); + assert.strictEqual(tests[0].label, 'CreateAndDestroy'); + assert.strictEqual(tests[0].file, undefined); + assert.strictEqual(tests[0].line, undefined); + assert.strictEqual(tests[0].skipped, false); + assert.strictEqual(tests[0].getStaticEvent('1'), undefined); + assert.strictEqual(tests[1].testNameAsId, 'SimpleMutexTest.LockUnlockTest'); + assert.strictEqual(tests[1].label, 'LockUnlockTest'); + assert.strictEqual(tests[1].file, undefined); + assert.strictEqual(tests[1].line, undefined); + assert.strictEqual(tests[1].skipped, false); + assert.strictEqual(tests[1].getStaticEvent('1'), undefined); + assert.strictEqual(tests[2].testNameAsId, 'TeamCityOutputTest.TestGroupEscaped_End'); + assert.strictEqual(tests[2].label, 'TestGroupEscaped_End'); + assert.strictEqual(tests[2].file, undefined); + assert.strictEqual(tests[2].line, undefined); + assert.strictEqual(tests[2].skipped, false); + assert.strictEqual(tests[2].getStaticEvent('1'), undefined); + assert.strictEqual(tests[3].testNameAsId, 'TeamCityOutputTest.TestNameEscaped_End'); + assert.strictEqual(tests[3].label, 'TestNameEscaped_End'); + assert.strictEqual(tests[3].file, undefined); + assert.strictEqual(tests[3].line, undefined); + assert.strictEqual(tests[3].skipped, false); + assert.strictEqual(tests[3].getStaticEvent('1'), undefined); + assert.strictEqual(tests[4].testNameAsId, 'TeamCityOutputTest.TestNameEscaped_Fail'); + assert.strictEqual(tests[4].label, 'TestNameEscaped_Fail'); + assert.strictEqual(tests[4].file, undefined); + assert.strictEqual(tests[4].line, undefined); + assert.strictEqual(tests[4].skipped, false); + assert.strictEqual(tests[4].getStaticEvent('1'), undefined); + assert.strictEqual(tests[5].testNameAsId, 'TeamCityOutputTest.TestNameEscaped_Ignore'); + assert.strictEqual(tests[5].label, 'TestNameEscaped_Ignore'); + assert.strictEqual(tests[5].file, undefined); + assert.strictEqual(tests[5].line, undefined); + assert.strictEqual(tests[5].skipped, false); + assert.strictEqual(tests[5].getStaticEvent('1'), undefined); + assert.strictEqual(tests[6].testNameAsId, 'TeamCityOutputTest.TestNameEscaped_Start'); + assert.strictEqual(tests[6].label, 'TestNameEscaped_Start'); + assert.strictEqual(tests[6].file, undefined); + assert.strictEqual(tests[6].line, undefined); + assert.strictEqual(tests[6].skipped, false); + assert.strictEqual(tests[6].getStaticEvent('1'), undefined); + assert.strictEqual(tests[7].testNameAsId, 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.CallToWaitPidFailedInSeparateProcessWorks'); + assert.strictEqual(tests[7].label, 'CallToWaitPidFailedInSeparateProcessWorks'); + assert.strictEqual(tests[7].file, undefined); + assert.strictEqual(tests[7].line, undefined); + assert.strictEqual(tests[7].skipped, false); + assert.strictEqual(tests[7].getStaticEvent('1'), undefined); + assert.strictEqual(tests[8].testNameAsId, 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.CallToWaitPidStopsAndReportsAnErrorAfter20TimesRetry'); + assert.strictEqual(tests[8].label, 'CallToWaitPidStopsAndReportsAnErrorAfter20TimesRetry'); + assert.strictEqual(tests[8].file, undefined); + assert.strictEqual(tests[8].line, undefined); + assert.strictEqual(tests[8].skipped, false); + assert.strictEqual(tests[8].getStaticEvent('1'), undefined); + assert.strictEqual(tests[9].testNameAsId, 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.MultipleTestsInSeparateProcessAreCountedProperly'); + assert.strictEqual(tests[9].label, 'MultipleTestsInSeparateProcessAreCountedProperly'); + assert.strictEqual(tests[9].file, undefined); + assert.strictEqual(tests[9].line, undefined); + assert.strictEqual(tests[9].skipped, false); + assert.strictEqual(tests[9].getStaticEvent('1'), undefined); + assert.strictEqual(tests[10].testNameAsId, 'UtestShellPointerArrayTest.reverse'); + assert.strictEqual(tests[10].label, 'reverse'); + assert.strictEqual(tests[10].file, undefined); + assert.strictEqual(tests[10].line, undefined); + assert.strictEqual(tests[10].skipped, false); + assert.strictEqual(tests[10].getStaticEvent('1'), undefined); + + assert.strictEqual(root.children.length, 1); + const suite1 = root.children[0]; + assert.strictEqual(suite1.label, 'name'); + if (suite1.type === 'suite') { + assert.strictEqual(suite1.children.length, 11); + } else { + assert.strictEqual(suite1.type, 'suite'); + } + }); + }); +}); diff --git a/test/framework/CppUTestTest.test.ts b/test/framework/CppUTestTest.test.ts new file mode 100644 index 00000000..f3e2696d --- /dev/null +++ b/test/framework/CppUTestTest.test.ts @@ -0,0 +1,109 @@ +import * as assert from 'assert'; +import * as path from 'path'; +import { CppUTestTest } from '../../src/framework/CppUTestTest'; +import { AbstractRunnable } from '../../src/AbstractRunnable'; +import { Suite } from '../../src/Suite'; +import { EOL } from 'os'; +import { TestRunEvent } from '../../src/SharedVariables'; +import { logger } from '../LogOutputContent.test'; + +describe(path.basename(__filename), function () { + const cpputest: CppUTestTest = new CppUTestTest( + { + log: logger, + }, + null as unknown as AbstractRunnable, + null as unknown as Suite, + 'TestCase.TestName', + 'TestName', + 'gtest.cpp', + 11, + ); + + it('parses failed test', function () { + const output = [ + 'TEST(UtestShell, PassedCheckEqualWillIncreaseTheAmountOfChecks)', + '/workspaces/cpputest-4.0/tests/CppUTest/UtestTest.cpp:90: error: Failure in TEST(UtestShell, PassedCheckEqualWillIncreaseTheAmountOfChecks)', + 'LONGS_EQUAL(10, fixture.getCheckCount()) failed', + 'expected <10 (0xa)>', + 'but was < 1 (0x1)>', + ' - 47 ms', + ].join(EOL); + + const ev = cpputest.parseAndProcessTestCase('runid', output, 42, null, ''); + + const expected: TestRunEvent = { + testRunId: 'runid', + type: 'test', + test: cpputest.id, + message: output, + state: 'failed', + description: '(47ms)', + tooltip: 'Name: TestCase.TestName\nā±Duration: 47ms', + decorations: [ + { + file: 'UtestTest.cpp', + hover: 'expected <10 (0xa)>\nbut was < 1 (0x1)>', + line: 89, + message: 'ā¬… expected <10 (0xa)>; but was < 1 (0x1)>', + }, + ], + }; + + assert.strictEqual(cpputest.description, ev.description); + assert.strictEqual(cpputest.tooltip, ev.tooltip); + assert.strictEqual(cpputest.lastRunMilisec, 47); + assert.deepStrictEqual(ev, expected); + assert.deepStrictEqual(cpputest.lastRunEvent, expected); + }); + + it('parses passed test', function () { + const output = [ + 'TEST(UtestShell, compareDoubles) - 30 ms', + ].join(EOL); + + const ev = cpputest.parseAndProcessTestCase('runid', output, 42, null, ''); + + const expected: TestRunEvent = { + testRunId: 'runid', + type: 'test', + test: cpputest.id, + message: output, + state: 'passed', + description: '(30ms)', + tooltip: 'Name: TestCase.TestName\nā±Duration: 30ms', + decorations: [], + }; + + assert.strictEqual(cpputest.description, ev.description); + assert.strictEqual(cpputest.tooltip, ev.tooltip); + assert.strictEqual(cpputest.lastRunMilisec, 30); + assert.deepStrictEqual(ev, expected); + assert.deepStrictEqual(cpputest.lastRunEvent, expected); + }); + + it('parses ignored test', function () { + const output = [ + 'IGNORE_TEST(UtestShell, IgnoreTestAccessingFixture) - 0 ms', + ].join(EOL); + + const ev = cpputest.parseAndProcessTestCase('runid', output, 0, null, ''); + + const expected: TestRunEvent = { + testRunId: 'runid', + type: 'test', + test: cpputest.id, + message: output, + state: 'skipped', + description: '(0ms)', + tooltip: 'Name: TestCase.TestName\nā±Duration: 0ms', + decorations: [], + }; + + assert.strictEqual(cpputest.description, ev.description); + assert.strictEqual(cpputest.tooltip, ev.tooltip); + assert.strictEqual(cpputest.lastRunMilisec, 0); + assert.deepStrictEqual(ev, expected); + assert.deepStrictEqual(cpputest.lastRunEvent, expected); + }); +}); From a3449ca21453e9e77e08e01f6b1c3de3480dceb5 Mon Sep 17 00:00:00 2001 From: Siza Date: Fri, 13 Aug 2021 12:04:00 +1200 Subject: [PATCH 02/18] Add CppUTest config settings --- package.json | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) diff --git a/package.json b/package.json index 3950b3f4..8f87353b 100644 --- a/package.json +++ b/package.json @@ -1334,6 +1334,240 @@ } } } + }, + "cpputest": { + "markdownDescription": "Object with framework specific settings. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#framework-specific-settings)", + "type": "object", + "additionalProperties": false, + "properties": { + "helpRegex": { + "markdownDescription": "A javascript [regex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) which will be used to recognise the framework. Flags: `su`. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md)", + "type": "string", + "minLength": 1 + }, + "prependTestRunningArgs": { + "markdownDescription": "Additinal argument array passed to the executable when it is called for testing. Good for experimental features like `[\"--benchmark-samples\", \"10\"]`. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md)", + "type": "array", + "items": { + "type": "string" + } + }, + "prependTestListingArgs": { + "markdownDescription": "Additinal argument array passed to the executable when it is called for test listing. (Discouraged. Try to use environment variables to pass values.) [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md)", + "type": "array", + "items": { + "type": "string" + } + }, + "debug.enableOutputColouring": { + "markdownDescription": "Sets the colouring of the output for debug session.", + "type": "boolean" + }, + "testGrouping": { + "markdownDescription": "Groups the tests inside the executable. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "additionalProperties": false, + "properties": { + "groupByExecutable": { + "markdownDescription": "Groups tests by the executable file. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "object", + "additionalProperties": false, + "properties": { + "label": { + "markdownDescription": "The label of the test executable. Can contains variables related to `pattern`. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "string" + }, + "description": { + "markdownDescription": "A less prominent text after the `label`. Can contains variables related to `pattern`. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "string" + }, + "groupByExecutable": { + "type": "object" + }, + "groupBySource": { + "type": "object" + }, + "groupByTags": { + "type": "object" + }, + "groupByTagRegex": { + "type": "object" + }, + "groupByRegex": { + "type": "object" + } + } + }, + "groupBySource": { + "markdownDescription": "Groups the tests by the source file. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "object", + "additionalProperties": false, + "properties": { + "label": { + "markdownDescription": "Label of the group. Can be indexed. (`${sourceRelPath}`, `${sourceAbsPath}`). [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "string" + }, + "description": { + "markdownDescription": "Less prominent text next to label. Can be indexed. (`${sourceRelPath}`, `${sourceAbsPath}`). [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "string" + }, + "groupUngroupedTo": { + "markdownDescription": "Ungroupable elements will be grouped under the given value. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "string", + "minLength": 1 + }, + "groupByExecutable": { + "type": "object" + }, + "groupBySource": { + "type": "object" + }, + "groupByTags": { + "type": "object" + }, + "groupByTagRegex": { + "type": "object" + }, + "groupByRegex": { + "type": "object" + } + }, + "required": [ + "sourceIndex" + ] + }, + "groupByTags": { + "markdownDescription": "Group test by tags. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "object", + "additionalProperties": false, + "properties": { + "tags": { + "markdownDescription": "True to group by every exiting combination of the tags. Or it can be an array of tags: `[\"[tag1][tag2]\", \"tag2\", \"tag3\"]` [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "array", + "items": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + } + }, + "tagFormat": { + "type": "string", + "pattern": "\\$\\{tag\\}" + }, + "groupUngroupedTo": { + "markdownDescription": "Ungroupable elements will be grouped under the given value. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "string", + "minLength": 1 + }, + "groupByExecutable": { + "type": "object" + }, + "groupBySource": { + "type": "object" + }, + "groupByTags": { + "type": "object" + }, + "groupByTagRegex": { + "type": "object" + }, + "groupByRegex": { + "type": "object" + } + } + }, + "groupByTagRegex": { + "markdownDescription": "Groups tests by the first match group of the first matching regex. (`${match}`, `${match_lowercased}`, `${match_upperfirst}`) Example: `[\"(?:good|bad) (apple|peach)\"]` will create 2 groups and put the matched tests inside it. Hint: Grouping starting with \"?:\" won't count as a match group. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "object", + "additionalProperties": false, + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "regexes": { + "markdownDescription": "Groups by the first match group (enclosed by parentheses like this). of the first matching [regex](https://regex101.com/). Example: `[\"(?:good|bad) (apple|peach)\"]` will create 2 groups and put the matched tests inside it. Hint: Grouping starting with \"?:\" won't count as a match group. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + }, + "groupUngroupedTo": { + "markdownDescription": "Ungroupable elements will be grouped under the given value. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "string", + "minLength": 1 + }, + "groupByExecutable": { + "type": "object" + }, + "groupBySource": { + "type": "object" + }, + "groupByTags": { + "type": "object" + }, + "groupByTagRegex": { + "type": "object" + }, + "groupByRegex": { + "type": "object" + } + }, + "required": [ + "regexes" + ] + }, + "groupByRegex": { + "markdownDescription": "Groups tests by the first match group of the first matching regex. (`${match}`, `${match_lowercased}`, `${match_upperfirst}`) Example: `[\"(?:good|bad) (apple|peach)\"]` will create 2 groups and put the matched tests inside it. Hint: Grouping starting with \"?:\" won't count as a match group. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "object", + "additionalProperties": false, + "properties": { + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "regexes": { + "markdownDescription": "Groups by the first match group (enclosed by parentheses like this). of the first matching [regex](https://regex101.com/). Example: `[\"(?:good|bad) (apple|peach)\"]` will create 2 groups and put the matched tests inside it. Hint: Grouping starting with \"?:\" won't count as a match group. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + }, + "groupUngroupedTo": { + "markdownDescription": "Ungroupable elements will be grouped under the given value. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#testgrouping)", + "type": "string", + "minLength": 1 + }, + "groupByExecutable": { + "type": "object" + }, + "groupBySource": { + "type": "object" + }, + "groupByTags": { + "type": "object" + }, + "groupByTagRegex": { + "type": "object" + }, + "groupByRegex": { + "type": "object" + } + }, + "required": [ + "regexes" + ] + } + } + } + } } }, "required": [ From 76c6c000563a3ceeb8c86397869a684207a5ab62 Mon Sep 17 00:00:00 2001 From: Siza Date: Sat, 14 Aug 2021 12:45:49 +1200 Subject: [PATCH 03/18] Tidy up! --- src/framework/CppUTestRunnable.ts | 35 +++++++------------------ src/framework/CppUTestTest.ts | 6 ----- test/framework/CppUTestRunnable.test.ts | 18 +++++++++---- 3 files changed, 22 insertions(+), 37 deletions(-) diff --git a/src/framework/CppUTestRunnable.ts b/src/framework/CppUTestRunnable.ts index a96e037d..ac1bd09e 100644 --- a/src/framework/CppUTestRunnable.ts +++ b/src/framework/CppUTestRunnable.ts @@ -20,18 +20,17 @@ export class CppUTestRunnable extends AbstractRunnable { shared: SharedVariables, rootSuite: RootSuite, execInfo: RunnableProperties, - // private readonly _argumentPrefix: string, version: Promise, ) { super(shared, rootSuite, execInfo, 'CppUTest', version); } private getTestGrouping(): TestGrouping { + // TODO: Reconsider grouping if (this.properties.testGrouping) { return this.properties.testGrouping; } else { const grouping = { groupByExecutable: this._getGroupByExecutable() }; - // grouping.groupByExecutable.groupByTags = { tags: [], tagFormat: '${tag}' }; return grouping; } } @@ -91,7 +90,6 @@ export class CppUTestRunnable extends AbstractRunnable { ): Promise { const testGrouping = this.getTestGrouping(); const lines = stdOutStr.split(' '); - // const testGroupList = [...new Set(lines.map(gs => gs.split(".")[0]))]; const reloadResult = new RunnableReloadResult(); @@ -158,6 +156,7 @@ export class CppUTestRunnable extends AbstractRunnable { const result = this._reloadFromString(cppUTestListOutput.stdout, cancellationFlag); if (this._shared.enabledTestListCaching) { + // TODO: Generate xml files in seperate folder such as xml_outputs //Generate xml files const args = this.properties.prependTestListingArgs.concat(['-ojunit']); this._shared.log.info('create cpputest xmls', this.properties.path, args, this.properties.options.cwd); @@ -188,33 +187,24 @@ export class CppUTestRunnable extends AbstractRunnable { } protected _getRunParamsInner(childrenToRun: readonly Readonly[]): string[] { - // TODO Add multiple options - // return ['-c', '-v']; - + // TODO: Add multiple options const execParams: string[] = []; - childrenToRun.forEach(t => { execParams.push(`TEST(${t.testNameAsId.split('.')[0]}, ${t.testNameAsId.split('.')[1]})`); }); - - // execParams.push(testNames.join(' ')); execParams.push('-c'); execParams.push('-v'); - return execParams; } protected _getDebugParamsInner(childrenToRun: readonly Readonly[], breakOnFailure: boolean): string[] { - // TODO colouring 'debug.enableOutputColouring' - // TODO Add multiple options - // return ['-c', '-v']; + // TODO: Proper debug options + // TODO: colouring 'debug.enableOutputColouring' + // TODO: Add multiple options const execParams: string[] = []; - childrenToRun.forEach(t => { execParams.push(`TEST(${t.testNameAsId.split('.')[0]}, ${t.testNameAsId.split('.')[1]})`); }); - - // execParams.push(testNames.join(' ')); execParams.push('-c'); execParams.push('-v'); @@ -223,7 +213,7 @@ export class CppUTestRunnable extends AbstractRunnable { protected _handleProcess(testRunId: string, runInfo: RunningRunnable): Promise { const data = new (class { - public stdoutAndErrBuffer = ''; // no reason to separate + public stdoutAndErrBuffer = ''; public currentTestCaseNameFull: string | undefined = undefined; public currentChild: AbstractTest | undefined = undefined; public route: Suite[] = []; @@ -266,12 +256,8 @@ export class CppUTestRunnable extends AbstractRunnable { data.stdoutAndErrBuffer = data.stdoutAndErrBuffer.substr(m.index!); } else { const testEndRe = / - \d+ ms$/m; - // const testEndRe = new RegExp( - // '(?!\\[ RUN \\])\\[..........\\] ' + data.currentTestCaseNameFull.replace('.', '\\.') + '.*$', - // 'm', - // ); - const m = data.stdoutAndErrBuffer.match(testEndRe); + if (m == null) return; const testCase = data.stdoutAndErrBuffer.substring(0, m.index! + m[0].length); @@ -286,9 +272,7 @@ export class CppUTestRunnable extends AbstractRunnable { runInfo.timeout, undefined, ); - this._shared.sendTestRunEvent(ev); - data.processedTestCases.push(data.currentChild); } catch (e) { this._shared.log.error('parsing and processing test', e, data); @@ -326,7 +310,6 @@ export class CppUTestRunnable extends AbstractRunnable { data.currentTestCaseNameFull = undefined; data.currentChild = undefined; - // do not clear data.route data.stdoutAndErrBuffer = data.stdoutAndErrBuffer.substr(m.index! + m[0].length); } } while (data.stdoutAndErrBuffer.length > 0 && --invariant > 0); @@ -426,7 +409,7 @@ export class CppUTestRunnable extends AbstractRunnable { ); events.push(ev); } catch (e) { - this._shared.log.error('parsing and processing test', e, testCase); + this._shared.log.error('parsing and processing test failed', e, testCase); } } events.length && this._shared.sendTestEvents(events); diff --git a/src/framework/CppUTestTest.ts b/src/framework/CppUTestTest.ts index 2994d770..fd7345df 100644 --- a/src/framework/CppUTestTest.ts +++ b/src/framework/CppUTestTest.ts @@ -71,17 +71,11 @@ export class CppUTestTest extends AbstractTest { try { const lines = output.split(/\r?\n/); - // if (lines.length < 1) throw new Error('unexpected'); - // const testName = lines[i].match(/\((.*)\)/)[1].split(',')[1].trim(); - const eventBuilder = new TestEventBuilder(this, testRunId); const runDuration = lines[lines.length - 1].match(/([0-9]+) ms/); eventBuilder.setDurationMilisec(runDuration ? Number(runDuration[1]) : undefined); - // const m = lines[i].match(endRe); - // if (m !== null) break; - const isSkipped = lines[0].indexOf('IGNORE_TEST') != -1; if (isSkipped) eventBuilder.skipped(); if (lines.length === 1) eventBuilder.passed(); diff --git a/test/framework/CppUTestRunnable.test.ts b/test/framework/CppUTestRunnable.test.ts index 6babea90..46077093 100644 --- a/test/framework/CppUTestRunnable.test.ts +++ b/test/framework/CppUTestRunnable.test.ts @@ -4,7 +4,6 @@ import { Imitation, SharedVariables } from '../Common'; import { CppUTestRunnable } from '../../src/framework/CppUTestRunnable'; import { RootSuite } from '../../src/RootSuite'; import { RunnableProperties } from '../../src/RunnableProperties'; -// import { EOL } from 'os'; import { DefaultSpawner } from '../../src/Spawner'; /// @@ -78,7 +77,7 @@ describe(pathlib.basename(__filename), function () { const res = await runnable['_reloadFromString'](testListOutput.join(' '), { isCancellationRequested: false }); const tests = [...res.tests].sort((a, b) => a.testNameAsId.localeCompare(b.testNameAsId)); - + assert.strictEqual(tests.length, 11); assert.strictEqual(tests[0].testNameAsId, 'SimpleMutexTest.CreateAndDestroy'); assert.strictEqual(tests[0].label, 'CreateAndDestroy'); @@ -122,19 +121,28 @@ describe(pathlib.basename(__filename), function () { assert.strictEqual(tests[6].line, undefined); assert.strictEqual(tests[6].skipped, false); assert.strictEqual(tests[6].getStaticEvent('1'), undefined); - assert.strictEqual(tests[7].testNameAsId, 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.CallToWaitPidFailedInSeparateProcessWorks'); + assert.strictEqual( + tests[7].testNameAsId, + 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.CallToWaitPidFailedInSeparateProcessWorks', + ); assert.strictEqual(tests[7].label, 'CallToWaitPidFailedInSeparateProcessWorks'); assert.strictEqual(tests[7].file, undefined); assert.strictEqual(tests[7].line, undefined); assert.strictEqual(tests[7].skipped, false); assert.strictEqual(tests[7].getStaticEvent('1'), undefined); - assert.strictEqual(tests[8].testNameAsId, 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.CallToWaitPidStopsAndReportsAnErrorAfter20TimesRetry'); + assert.strictEqual( + tests[8].testNameAsId, + 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.CallToWaitPidStopsAndReportsAnErrorAfter20TimesRetry', + ); assert.strictEqual(tests[8].label, 'CallToWaitPidStopsAndReportsAnErrorAfter20TimesRetry'); assert.strictEqual(tests[8].file, undefined); assert.strictEqual(tests[8].line, undefined); assert.strictEqual(tests[8].skipped, false); assert.strictEqual(tests[8].getStaticEvent('1'), undefined); - assert.strictEqual(tests[9].testNameAsId, 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.MultipleTestsInSeparateProcessAreCountedProperly'); + assert.strictEqual( + tests[9].testNameAsId, + 'UTestPlatformsTest_PlatformSpecificRunTestInASeperateProcess.MultipleTestsInSeparateProcessAreCountedProperly', + ); assert.strictEqual(tests[9].label, 'MultipleTestsInSeparateProcessAreCountedProperly'); assert.strictEqual(tests[9].file, undefined); assert.strictEqual(tests[9].line, undefined); From 1122366c508ba8dc7d37b5b4581d9226c7e34e8e Mon Sep 17 00:00:00 2001 From: Siza Date: Sat, 14 Aug 2021 21:53:07 +1200 Subject: [PATCH 04/18] Use temp xml folder during junit-xml creation --- src/framework/CppUTestRunnable.ts | 48 ++++++++++++++----------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/src/framework/CppUTestRunnable.ts b/src/framework/CppUTestRunnable.ts index ac1bd09e..57e69f46 100644 --- a/src/framework/CppUTestRunnable.ts +++ b/src/framework/CppUTestRunnable.ts @@ -1,7 +1,5 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as glob from 'glob'; -import { inspect, promisify } from 'util'; +import * as fs from 'fs-extra'; +import { inspect } from 'util'; import { mergeFiles } from 'junit-report-merger'; import { Suite } from '../Suite'; import { AbstractRunnable, RunnableReloadResult } from '../AbstractRunnable'; @@ -119,12 +117,12 @@ export class CppUTestRunnable extends AbstractRunnable { if (this._shared.enabledTestListCaching) { try { - const cacheStat = await promisify(fs.stat)(cacheFile); - const execStat = await promisify(fs.stat)(this.properties.path); + const cacheStat = await fs.stat(cacheFile); + const execStat = await fs.stat(this.properties.path); if (cacheStat.size > 0 && cacheStat.mtime > execStat.mtime) { this._shared.log.info('loading from cache: ', cacheFile); - const xmlStr = await promisify(fs.readFile)(cacheFile, 'utf8'); + const xmlStr = await fs.readFile(cacheFile, 'utf8'); return await this._reloadFromXml(xmlStr, cancellationFlag); } @@ -156,32 +154,30 @@ export class CppUTestRunnable extends AbstractRunnable { const result = this._reloadFromString(cppUTestListOutput.stdout, cancellationFlag); if (this._shared.enabledTestListCaching) { - // TODO: Generate xml files in seperate folder such as xml_outputs //Generate xml files + const junitXmlsFolderPath = this.properties.path + '_junit_xmls'; + if (!fs.existsSync(junitXmlsFolderPath)) { + fs.mkdir(junitXmlsFolderPath, err => { + if (err) this._shared.log.error('error creating xmls folder: ', junitXmlsFolderPath, err); + }); + } const args = this.properties.prependTestListingArgs.concat(['-ojunit']); - this._shared.log.info('create cpputest xmls', this.properties.path, args, this.properties.options.cwd); - await this.properties.spawner.spawnAsync(this.properties.path, args, this.properties.options, 30000); + const options = this.properties.options; + options.cwd = junitXmlsFolderPath; + this._shared.log.info('create cpputest xmls', this.properties.path, args, options.cwd); + await this.properties.spawner.spawnAsync(this.properties.path, args, options, 30000); try { - await mergeFiles(cacheFile, [path.dirname(this.properties.path) + '/*.xml']); + await mergeFiles(cacheFile, [junitXmlsFolderPath + '/*.xml']); this._shared.log.info('cache xml written: ', cacheFile); - //Delete xml files - const currentFolder = path.dirname(this.properties.path); - glob(currentFolder + '/cpputest_*.xml', { cwd: currentFolder }, (err, files) => { - if (err) { - this._shared.log.debug('error finding xml files: ', currentFolder, err); - } - - for (const file of files) { - try { - fs.unlinkSync(file); - } catch (err) { - this._shared.log.warn('cache file could not delete: ', file, err); - } - } - }); } catch (err) { this._shared.log.warn('combine xml cache file could not create: ', cacheFile, err); } + //Delete xmls folder + if (fs.existsSync(junitXmlsFolderPath)) { + fs.remove(junitXmlsFolderPath, err => { + if (err) this._shared.log.error('error deleting xmls folder: ', junitXmlsFolderPath, err); + }); + } } return result; } From 7605741597617fc6c75b18b785f3027a5ffac9cf Mon Sep 17 00:00:00 2001 From: Siza Date: Fri, 20 Aug 2021 18:48:22 +1200 Subject: [PATCH 05/18] Refactor --- src/framework/CppUTestRunnable.ts | 34 ++++++++++++++----------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/framework/CppUTestRunnable.ts b/src/framework/CppUTestRunnable.ts index 57e69f46..bddca6ce 100644 --- a/src/framework/CppUTestRunnable.ts +++ b/src/framework/CppUTestRunnable.ts @@ -154,30 +154,26 @@ export class CppUTestRunnable extends AbstractRunnable { const result = this._reloadFromString(cppUTestListOutput.stdout, cancellationFlag); if (this._shared.enabledTestListCaching) { - //Generate xml files + //Generate xmls folder const junitXmlsFolderPath = this.properties.path + '_junit_xmls'; - if (!fs.existsSync(junitXmlsFolderPath)) { - fs.mkdir(junitXmlsFolderPath, err => { - if (err) this._shared.log.error('error creating xmls folder: ', junitXmlsFolderPath, err); - }); - } + fs.mkdir(junitXmlsFolderPath) + .then(() => this._shared.log.info('junit-xmls folder created', junitXmlsFolderPath)) + .catch(err => this._shared.log.error('error creating xmls folder: ', junitXmlsFolderPath, err)); + //Generate xml files const args = this.properties.prependTestListingArgs.concat(['-ojunit']); const options = this.properties.options; options.cwd = junitXmlsFolderPath; - this._shared.log.info('create cpputest xmls', this.properties.path, args, options.cwd); - await this.properties.spawner.spawnAsync(this.properties.path, args, options, 30000); - try { - await mergeFiles(cacheFile, [junitXmlsFolderPath + '/*.xml']); - this._shared.log.info('cache xml written: ', cacheFile); - } catch (err) { - this._shared.log.warn('combine xml cache file could not create: ', cacheFile, err); - } + await this.properties.spawner + .spawnAsync(this.properties.path, args, options, 30000) + .then(() => this._shared.log.info('create cpputest xmls', this.properties.path, args, options.cwd)); + //Merge xmls into single xml + await mergeFiles(cacheFile, [junitXmlsFolderPath + '/*.xml']) + .then(() => this._shared.log.info('cache xml written', cacheFile)) + .catch(err => this._shared.log.warn('combine xml cache file could not create: ', cacheFile, err)); //Delete xmls folder - if (fs.existsSync(junitXmlsFolderPath)) { - fs.remove(junitXmlsFolderPath, err => { - if (err) this._shared.log.error('error deleting xmls folder: ', junitXmlsFolderPath, err); - }); - } + fs.remove(junitXmlsFolderPath) + .then(() => this._shared.log.info('junit-xmls folder deleted', junitXmlsFolderPath)) + .catch(err => this._shared.log.error('error deleting xmls folder: ', junitXmlsFolderPath, err)); } return result; } From 8af1868d8bbf1ff15d5183c126bbf48da254b22e Mon Sep 17 00:00:00 2001 From: Siza Date: Fri, 20 Aug 2021 18:52:14 +1200 Subject: [PATCH 06/18] Fix failed with multilines --- src/framework/CppUTestTest.ts | 22 ++++++------ test/framework/CppUTestTest.test.ts | 55 ++++++++++++++++++++++++++--- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/framework/CppUTestTest.ts b/src/framework/CppUTestTest.ts index fd7345df..58997798 100644 --- a/src/framework/CppUTestTest.ts +++ b/src/framework/CppUTestTest.ts @@ -67,7 +67,7 @@ export class CppUTestTest extends AbstractTest { this.lastRunEvent = ev; return ev; } - + //TODO: Refactor following codes try { const lines = output.split(/\r?\n/); @@ -76,18 +76,20 @@ export class CppUTestTest extends AbstractTest { const runDuration = lines[lines.length - 1].match(/([0-9]+) ms/); eventBuilder.setDurationMilisec(runDuration ? Number(runDuration[1]) : undefined); - const isSkipped = lines[0].indexOf('IGNORE_TEST') != -1; + let failedTest: RegExpMatchArray | null = null; + //Ignored tests will be never gets here because tests were run individually + const isSkipped = lines[0].match(/^IGNORE_TEST/); if (isSkipped) eventBuilder.skipped(); - if (lines.length === 1) eventBuilder.passed(); + if (lines.length > 1) { + failedTest = lines[1].match(CppUTestTest.failureRe); + } + if (failedTest === null) eventBuilder.passed(); else eventBuilder.failed(); - if (!isSkipped && lines.length > 1) { - const match = lines[1].match(CppUTestTest.failureRe); - if (match !== null) { - const filePath = match[2].split('/').pop(); - const lineNumber = Number(match[3]) - 1; - eventBuilder.appendDecorator(filePath, lineNumber, [lines[3], lines[4]]); - } + if (lines.length > 1 && failedTest !== null) { + const filePath = failedTest[2].split('/').pop(); + const lineNumber = Number(failedTest[3]) - 1; + eventBuilder.appendDecorator(filePath, lineNumber, [lines[3], lines[4]]); } const event = eventBuilder.build(output.replace(/\): error: /g, '): error: \n')); diff --git a/test/framework/CppUTestTest.test.ts b/test/framework/CppUTestTest.test.ts index f3e2696d..32454238 100644 --- a/test/framework/CppUTestTest.test.ts +++ b/test/framework/CppUTestTest.test.ts @@ -58,9 +58,7 @@ describe(path.basename(__filename), function () { }); it('parses passed test', function () { - const output = [ - 'TEST(UtestShell, compareDoubles) - 30 ms', - ].join(EOL); + const output = ['TEST(UtestShell, compareDoubles) - 30 ms'].join(EOL); const ev = cpputest.parseAndProcessTestCase('runid', output, 42, null, ''); @@ -82,11 +80,58 @@ describe(path.basename(__filename), function () { assert.deepStrictEqual(cpputest.lastRunEvent, expected); }); - it('parses ignored test', function () { + it('parses passed test with multilines', function () { + const output = ['TEST(UtestShell, compareDoubles)', ' - 30 ms'].join(EOL); + + const ev = cpputest.parseAndProcessTestCase('runid', output, 42, null, ''); + + const expected: TestRunEvent = { + testRunId: 'runid', + type: 'test', + test: cpputest.id, + message: output, + state: 'passed', + description: '(30ms)', + tooltip: 'Name: TestCase.TestName\nā±Duration: 30ms', + decorations: [], + }; + + assert.strictEqual(cpputest.description, ev.description); + assert.strictEqual(cpputest.tooltip, ev.tooltip); + assert.strictEqual(cpputest.lastRunMilisec, 30); + assert.deepStrictEqual(ev, expected); + assert.deepStrictEqual(cpputest.lastRunEvent, expected); + }); + + it('parses passed multilines test with extra texts', function () { const output = [ - 'IGNORE_TEST(UtestShell, IgnoreTestAccessingFixture) - 0 ms', + 'TEST(UtestShell, compareDoubles) Assertion fail /workspaces/user/app/base/system/workqueue.c:34', + ' - 10 ms', ].join(EOL); + const ev = cpputest.parseAndProcessTestCase('runid', output, 42, null, ''); + + const expected: TestRunEvent = { + testRunId: 'runid', + type: 'test', + test: cpputest.id, + message: output, + state: 'passed', + description: '(10ms)', + tooltip: 'Name: TestCase.TestName\nā±Duration: 10ms', + decorations: [], + }; + + assert.strictEqual(cpputest.description, ev.description); + assert.strictEqual(cpputest.tooltip, ev.tooltip); + assert.strictEqual(cpputest.lastRunMilisec, 10); + assert.deepStrictEqual(ev, expected); + assert.deepStrictEqual(cpputest.lastRunEvent, expected); + }); + + it('parses ignored test', function () { + const output = ['IGNORE_TEST(UtestShell, IgnoreTestAccessingFixture) - 0 ms'].join(EOL); + const ev = cpputest.parseAndProcessTestCase('runid', output, 0, null, ''); const expected: TestRunEvent = { From ec441a36fdfe55ec20a1df87b1ff1764ba13c659 Mon Sep 17 00:00:00 2001 From: Siza Date: Fri, 20 Aug 2021 18:53:52 +1200 Subject: [PATCH 07/18] Add skipped/notran tests in test suite tooltips --- src/Suite.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Suite.ts b/src/Suite.ts index 05431517..e4f056c1 100644 --- a/src/Suite.ts +++ b/src/Suite.ts @@ -161,6 +161,11 @@ export class Suite implements TestSuiteInfo { .map(state => ' - ' + state + ': ' + stateStat[state]) .join('\n'); + const skipOrNotRun = testCount - Object.values(stateStat).reduce((a, b) => a + b, 0); + if (skipOrNotRun !== 0) { + this._additionalTooltip += '\n - NotRan: ' + skipOrNotRun; + } + if (durationSum !== undefined) { const durationStr = milisecToStr(durationSum); From 400346b7071fbf16a509d00a9f34635c2c533003 Mon Sep 17 00:00:00 2001 From: Siza Date: Sat, 21 Aug 2021 16:17:01 +1200 Subject: [PATCH 08/18] Update documentation with CppUTest --- documents/configuration/test.advancedExecutables.md | 5 +++++ src/framework/CppUTestRunnable.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/documents/configuration/test.advancedExecutables.md b/documents/configuration/test.advancedExecutables.md index b6a7145a..d1758b5c 100644 --- a/documents/configuration/test.advancedExecutables.md +++ b/documents/configuration/test.advancedExecutables.md @@ -64,6 +64,7 @@ If it is an object it can contains the following properties: | `gtest` | Object with framework specific settings. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#framework-specific-settings) | | `doctest` | Object with framework specific settings. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#framework-specific-settings) | | `gbenchmark` | Object with framework specific settings. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#framework-specific-settings) | +| `cpputest` | Object with framework specific settings. [Detail](https://github.com/matepek/vscode-catch2-test-adapter/blob/master/documents/configuration/test.advancedExecutables.md#framework-specific-settings) | The `pattern` (or the `executables` used as string or an array of strings) can contain [_search-pattern_](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options). @@ -246,6 +247,10 @@ For example: - `Catch v2.11.1` + `/Catch v(\d+)\.(\d+)\.(\d+)\s?/` -> `[2, 11, 1]` +In case of `cpputest` the helpRegex can be as following. + +- `[-g|sg|xg|xsg groupName]... [-n|sn|xn|xsn testName]...` + ### ignoreTestEnumerationStdErr As the name says test enumeraton will ignore std::err output. diff --git a/src/framework/CppUTestRunnable.ts b/src/framework/CppUTestRunnable.ts index bddca6ce..9708ce52 100644 --- a/src/framework/CppUTestRunnable.ts +++ b/src/framework/CppUTestRunnable.ts @@ -24,7 +24,7 @@ export class CppUTestRunnable extends AbstractRunnable { } private getTestGrouping(): TestGrouping { - // TODO: Reconsider grouping + // TODO: Consider grouping based on passed/failed if (this.properties.testGrouping) { return this.properties.testGrouping; } else { From 168ad5214414207dcc91d305f3263cb18e5a8858 Mon Sep 17 00:00:00 2001 From: Siza Date: Sun, 22 Aug 2021 17:33:50 +1200 Subject: [PATCH 09/18] Fix tooltip --- src/framework/CppUTestTest.ts | 4 ++- test/framework/CppUTestTest.test.ts | 45 +++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/framework/CppUTestTest.ts b/src/framework/CppUTestTest.ts index 58997798..1e8c677e 100644 --- a/src/framework/CppUTestTest.ts +++ b/src/framework/CppUTestTest.ts @@ -89,7 +89,9 @@ export class CppUTestTest extends AbstractTest { if (lines.length > 1 && failedTest !== null) { const filePath = failedTest[2].split('/').pop(); const lineNumber = Number(failedTest[3]) - 1; - eventBuilder.appendDecorator(filePath, lineNumber, [lines[3], lines[4]]); + const expected = lines.find(value => /^\texpected/.test(value)); + const actual = lines.find(value => /^\tbut was/.test(value)); + eventBuilder.appendDecorator(filePath, lineNumber, [expected ? expected : '', actual ? actual : '']); } const event = eventBuilder.build(output.replace(/\): error: /g, '): error: \n')); diff --git a/test/framework/CppUTestTest.test.ts b/test/framework/CppUTestTest.test.ts index 32454238..25615158 100644 --- a/test/framework/CppUTestTest.test.ts +++ b/test/framework/CppUTestTest.test.ts @@ -25,8 +25,8 @@ describe(path.basename(__filename), function () { 'TEST(UtestShell, PassedCheckEqualWillIncreaseTheAmountOfChecks)', '/workspaces/cpputest-4.0/tests/CppUTest/UtestTest.cpp:90: error: Failure in TEST(UtestShell, PassedCheckEqualWillIncreaseTheAmountOfChecks)', 'LONGS_EQUAL(10, fixture.getCheckCount()) failed', - 'expected <10 (0xa)>', - 'but was < 1 (0x1)>', + '\texpected <10 (0xa)>', + '\tbut was < 1 (0x1)>', ' - 47 ms', ].join(EOL); @@ -43,7 +43,7 @@ describe(path.basename(__filename), function () { decorations: [ { file: 'UtestTest.cpp', - hover: 'expected <10 (0xa)>\nbut was < 1 (0x1)>', + hover: '\texpected <10 (0xa)>\n\tbut was < 1 (0x1)>', line: 89, message: 'ā¬… expected <10 (0xa)>; but was < 1 (0x1)>', }, @@ -57,6 +57,45 @@ describe(path.basename(__filename), function () { assert.deepStrictEqual(cpputest.lastRunEvent, expected); }); + it('parses another failed test', function () { + const output = [ + 'TEST(read_rssi, min_rssi_with_min_gain)', + '/workspaces/cpputest-4.0/tests/CppUTest/test_read_rssi.cpp:176: error: Failure in TEST(read_rssi, min_rssi_with_min_gain)', + '\texpected <-1984>', + '\tbut was <-1987>', + 'difference starts at position 4 at: < -1987 >', + ' ^', + '', + '- 47 ms', + ].join(EOL); + + const ev = cpputest.parseAndProcessTestCase('runid', output, 42, null, ''); + + const expected: TestRunEvent = { + testRunId: 'runid', + type: 'test', + test: cpputest.id, + message: output, + state: 'failed', + description: '(47ms)', + tooltip: 'Name: TestCase.TestName\nā±Duration: 47ms', + decorations: [ + { + file: 'test_read_rssi.cpp', + hover: '\texpected <-1984>\n\tbut was <-1987>', + line: 175, + message: 'ā¬… expected <-1984>; but was <-1987>', + }, + ], + }; + + assert.strictEqual(cpputest.description, ev.description); + assert.strictEqual(cpputest.tooltip, ev.tooltip); + assert.strictEqual(cpputest.lastRunMilisec, 47); + assert.deepStrictEqual(ev, expected); + assert.deepStrictEqual(cpputest.lastRunEvent, expected); + }); + it('parses passed test', function () { const output = ['TEST(UtestShell, compareDoubles) - 30 ms'].join(EOL); From 0b24fcf467b536f0508e0bce4f003d2b8c08798e Mon Sep 17 00:00:00 2001 From: Siza Date: Sun, 22 Aug 2021 18:42:34 +1200 Subject: [PATCH 10/18] Update CHANGELOG --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index baddfcb4..1b7280ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] -## [3.6.27] +## [3.7.0] - 2021-08-21 + +Feature Added: CppUTest Framework Support with tests + +## [3.6.27] - 2021-08-09 + +NPM update +Moving to travis-ci.com +Minified code ## [3.6.26] - 2021-04-27 From 2d2d7b293463f857fecd0c0904886a06ce8bb301 Mon Sep 17 00:00:00 2001 From: Siza Date: Sun, 22 Aug 2021 18:42:53 +1200 Subject: [PATCH 11/18] Update README --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 495ddf63..94575b03 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # C++ TestMate -## A **Catch2**, **GoogleTest**, **doctest** and **GoogleBenchmark** Explorer for VSCode +## A **Catch2**, **GoogleTest**, **CppUTest**, **doctest** and **GoogleBenchmark** Explorer for VSCode [![Visual Studio Marketplace](https://img.shields.io/vscode-marketplace/v/matepek.vscode-catch2-test-adapter.svg)](https://marketplace.visualstudio.com/items?itemName=matepek.vscode-catch2-test-adapter) [![GitHub issues](https://img.shields.io/github/issues/matepek/vscode-catch2-test-adapter?color=green)](https://github.com/matepek/vscode-catch2-test-adapter/issues) @@ -8,8 +8,7 @@ [![Gitter](https://badges.gitter.im/CppTestMate/community.svg)](https://gitter.im/CppTestMate/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) This extension allows you to run your [Catch2](https://github.com/catchorg/Catch2), -[Google Test](https://github.com/google/googletest) -and [DOCtest](https://github.com/onqtam/doctest) +[Google Test](https://github.com/google/googletest), [CppUTest](https://github.com/cpputest/cpputest) and [DOCtest](https://github.com/onqtam/doctest) tests using the [Test Explorer for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-test-explorer). It also have basic support for [Google Benchmark](https://github.com/google/benchmark). From c9ca98eaed662ec69959144e05d56f99034b3162 Mon Sep 17 00:00:00 2001 From: Mate Pek Date: Mon, 23 Aug 2021 12:03:06 +0200 Subject: [PATCH 12/18] cpp tests: not working --- package-lock.json | 240 ++++++++++++++++++++++++------ src/framework/CppUTestRunnable.ts | 1 - test/cpp/CMakeLists.txt | 1 + test/cpp/cpputest/CMakeLists.txt | 3 + test/cpp/cpputest/CppUTest.cmake | 13 ++ test/cpp/cpputest/cpputest1.cpp | 29 ++++ 6 files changed, 238 insertions(+), 49 deletions(-) create mode 100644 test/cpp/cpputest/CMakeLists.txt create mode 100644 test/cpp/cpputest/CppUTest.cmake create mode 100644 test/cpp/cpputest/cpputest1.cpp diff --git a/package-lock.json b/package-lock.json index f5711615..f714f82d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,11 +5,13 @@ "requires": true, "packages": { "": { + "name": "vscode-catch2-test-adapter", "version": "3.6.26", "license": "MIT", "dependencies": { "@types/ps-node": "^0.1.1", "gaze": "^1.1.3", + "junit-report-merger": "^2.2.3", "ovsx": "^0.2.0", "ps-node": "^0.1.6", "tslib": "^2.3.1", @@ -215,7 +217,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -228,7 +229,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -237,7 +237,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -246,6 +245,50 @@ "node": ">= 8" } }, + "node_modules/@oozcitak/dom": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-1.15.8.tgz", + "integrity": "sha512-MoOnLBNsF+ok0HjpAvxYxR4piUhRDCEWK0ot3upwOOHYudJd30j6M+LNcE8RKpwfnclAX9T66nXXzkytd29XSw==", + "dependencies": { + "@oozcitak/infra": "1.0.8", + "@oozcitak/url": "1.0.4", + "@oozcitak/util": "8.3.8" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@oozcitak/infra": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.8.tgz", + "integrity": "sha512-JRAUc9VR6IGHOL7OGF+yrvs0LO8SlqGnPAMqyzOuFZPSZSXI7Xf2O9+awQPSMXgIWGtgUf/dA6Hs6X6ySEaWTg==", + "dependencies": { + "@oozcitak/util": "8.3.8" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/@oozcitak/url": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-1.0.4.tgz", + "integrity": "sha512-kDcD8y+y3FCSOvnBI6HJgl00viO/nGbQoCINmQ0h98OhnGITrWR3bOGfwYCthgcrV8AnTJz8MzslTQbC3SOAmw==", + "dependencies": { + "@oozcitak/infra": "1.0.8", + "@oozcitak/util": "8.3.8" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@oozcitak/util": { + "version": "8.3.8", + "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.3.8.tgz", + "integrity": "sha512-T8TbSnGsxo6TDBJx/Sgv/BlVJL3tshxZP7Aq5R1mSnM5OcHY2dQaxLMu2+E8u3gN0MLOzdjurqN4ZRVuzQycOQ==", + "engines": { + "node": ">=8.0" + } + }, "node_modules/@polka/url": { "version": "1.0.0-next.17", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.17.tgz", @@ -543,8 +586,7 @@ "node_modules/@types/node": { "version": "16.6.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.6.2.tgz", - "integrity": "sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA==", - "dev": true + "integrity": "sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA==" }, "node_modules/@types/ps-node": { "version": "0.1.1", @@ -1215,7 +1257,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -2098,7 +2139,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -2249,7 +2289,6 @@ "version": "1.12.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.12.0.tgz", "integrity": "sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -2278,7 +2317,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2657,7 +2695,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -3073,7 +3110,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3091,7 +3127,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -3124,7 +3159,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -3395,6 +3429,37 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/junit-report-merger": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/junit-report-merger/-/junit-report-merger-2.2.3.tgz", + "integrity": "sha512-bddxE3rxoNGAt1LB5eIBbkQKluDMa2WWExsFjjtwaG0s0wQHxvDcD6OYH8t4i/8J/gv5h309NyQK23AiGFSSUA==", + "dependencies": { + "fast-glob": "3.2.6", + "xmlbuilder2": "2.4.1" + }, + "bin": { + "jrm": "cli.js", + "junit-report-merger": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/junit-report-merger/node_modules/fast-glob": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.6.tgz", + "integrity": "sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/just-extend": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", @@ -3581,7 +3646,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } @@ -3590,7 +3654,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, "dependencies": { "braces": "^3.0.1", "picomatch": "^2.2.3" @@ -4358,7 +4421,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -4513,7 +4575,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -4728,7 +4789,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -4752,7 +4812,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -5229,7 +5288,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -5996,6 +6054,33 @@ "node": ">=4.0" } }, + "node_modules/xmlbuilder2": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-2.4.1.tgz", + "integrity": "sha512-vliUplZsk5vJnhxXN/mRcij/AE24NObTUm/Zo4vkLusgayO6s3Et5zLEA14XZnY1c3hX5o1ToR0m0BJOPy0UvQ==", + "dependencies": { + "@oozcitak/dom": "1.15.8", + "@oozcitak/infra": "1.0.8", + "@oozcitak/util": "8.3.8", + "@types/node": "*", + "js-yaml": "3.14.0" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/xmlbuilder2/node_modules/js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -6212,7 +6297,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "requires": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -6221,19 +6305,49 @@ "@nodelib/fs.stat": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" }, "@nodelib/fs.walk": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, + "@oozcitak/dom": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-1.15.8.tgz", + "integrity": "sha512-MoOnLBNsF+ok0HjpAvxYxR4piUhRDCEWK0ot3upwOOHYudJd30j6M+LNcE8RKpwfnclAX9T66nXXzkytd29XSw==", + "requires": { + "@oozcitak/infra": "1.0.8", + "@oozcitak/url": "1.0.4", + "@oozcitak/util": "8.3.8" + } + }, + "@oozcitak/infra": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.8.tgz", + "integrity": "sha512-JRAUc9VR6IGHOL7OGF+yrvs0LO8SlqGnPAMqyzOuFZPSZSXI7Xf2O9+awQPSMXgIWGtgUf/dA6Hs6X6ySEaWTg==", + "requires": { + "@oozcitak/util": "8.3.8" + } + }, + "@oozcitak/url": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-1.0.4.tgz", + "integrity": "sha512-kDcD8y+y3FCSOvnBI6HJgl00viO/nGbQoCINmQ0h98OhnGITrWR3bOGfwYCthgcrV8AnTJz8MzslTQbC3SOAmw==", + "requires": { + "@oozcitak/infra": "1.0.8", + "@oozcitak/util": "8.3.8" + } + }, + "@oozcitak/util": { + "version": "8.3.8", + "resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.3.8.tgz", + "integrity": "sha512-T8TbSnGsxo6TDBJx/Sgv/BlVJL3tshxZP7Aq5R1mSnM5OcHY2dQaxLMu2+E8u3gN0MLOzdjurqN4ZRVuzQycOQ==" + }, "@polka/url": { "version": "1.0.0-next.17", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.17.tgz", @@ -6518,8 +6632,7 @@ "@types/node": { "version": "16.6.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.6.2.tgz", - "integrity": "sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA==", - "dev": true + "integrity": "sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA==" }, "@types/ps-node": { "version": "0.1.1", @@ -7044,7 +7157,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -7693,8 +7805,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esquery": { "version": "1.4.0", @@ -7812,7 +7923,6 @@ "version": "1.12.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.12.0.tgz", "integrity": "sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==", - "dev": true, "requires": { "reusify": "^1.0.4" } @@ -7838,7 +7948,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -8119,7 +8228,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -8406,8 +8514,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -8419,7 +8526,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -8439,8 +8545,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-number-object": { "version": "1.0.6", @@ -8630,6 +8735,29 @@ "universalify": "^2.0.0" } }, + "junit-report-merger": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/junit-report-merger/-/junit-report-merger-2.2.3.tgz", + "integrity": "sha512-bddxE3rxoNGAt1LB5eIBbkQKluDMa2WWExsFjjtwaG0s0wQHxvDcD6OYH8t4i/8J/gv5h309NyQK23AiGFSSUA==", + "requires": { + "fast-glob": "3.2.6", + "xmlbuilder2": "2.4.1" + }, + "dependencies": { + "fast-glob": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.6.tgz", + "integrity": "sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + } + } + }, "just-extend": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", @@ -8784,14 +8912,12 @@ "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, "micromatch": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, "requires": { "braces": "^3.0.1", "picomatch": "^2.2.3" @@ -9383,8 +9509,7 @@ "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" }, "pkg-dir": { "version": "4.2.0", @@ -9492,8 +9617,7 @@ "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, "randombytes": { "version": "2.1.0", @@ -9645,8 +9769,7 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, "rimraf": { "version": "3.0.2", @@ -9660,7 +9783,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "requires": { "queue-microtask": "^1.2.2" } @@ -10011,7 +10133,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } @@ -10579,6 +10700,29 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" }, + "xmlbuilder2": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-2.4.1.tgz", + "integrity": "sha512-vliUplZsk5vJnhxXN/mRcij/AE24NObTUm/Zo4vkLusgayO6s3Et5zLEA14XZnY1c3hX5o1ToR0m0BJOPy0UvQ==", + "requires": { + "@oozcitak/dom": "1.15.8", + "@oozcitak/infra": "1.0.8", + "@oozcitak/util": "8.3.8", + "@types/node": "*", + "js-yaml": "3.14.0" + }, + "dependencies": { + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } + } + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/src/framework/CppUTestRunnable.ts b/src/framework/CppUTestRunnable.ts index 9708ce52..d2626fa0 100644 --- a/src/framework/CppUTestRunnable.ts +++ b/src/framework/CppUTestRunnable.ts @@ -24,7 +24,6 @@ export class CppUTestRunnable extends AbstractRunnable { } private getTestGrouping(): TestGrouping { - // TODO: Consider grouping based on passed/failed if (this.properties.testGrouping) { return this.properties.testGrouping; } else { diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt index 6ad32cb2..3cbfc6bf 100644 --- a/test/cpp/CMakeLists.txt +++ b/test/cpp/CMakeLists.txt @@ -24,4 +24,5 @@ add_subdirectory("catch2") add_subdirectory("gtest") add_subdirectory("doctest") add_subdirectory("gbenchmark") +add_subdirectory("cpputest") add_subdirectory("misc") \ No newline at end of file diff --git a/test/cpp/cpputest/CMakeLists.txt b/test/cpp/cpputest/CMakeLists.txt new file mode 100644 index 00000000..f393c084 --- /dev/null +++ b/test/cpp/cpputest/CMakeLists.txt @@ -0,0 +1,3 @@ +include("CppUTest.cmake") + +add_cpputest_with_main(cpputest1 "cpputest1.cpp") \ No newline at end of file diff --git a/test/cpp/cpputest/CppUTest.cmake b/test/cpp/cpputest/CppUTest.cmake new file mode 100644 index 00000000..d13b92e6 --- /dev/null +++ b/test/cpp/cpputest/CppUTest.cmake @@ -0,0 +1,13 @@ +include(FetchContent) + +FetchContent_Declare(cpputest + GIT_REPOSITORY https://github.com/cpputest/cpputest.git + GIT_TAG latest-passing-build) + +set(TESTS OFF CACHE BOOL "Switch off CppUTest Test build") +FetchContent_MakeAvailable(cpputest) + +function(add_cpputest_with_main target cpp_file) + add_executable(${target} "${cpp_file}") + target_link_libraries(${target} PRIVATE CppUTest CppUTestExt) +endfunction() \ No newline at end of file diff --git a/test/cpp/cpputest/cpputest1.cpp b/test/cpp/cpputest/cpputest1.cpp new file mode 100644 index 00000000..ebdf1277 --- /dev/null +++ b/test/cpp/cpputest/cpputest1.cpp @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include + +#include "CppUTest/TestHarness.h" +#include "CppUTest/CommandLineTestRunner.h" +using namespace std; + +TEST_GROUP(FirstTestGroup) +{ +}; + +TEST(FirstTestGroup, FirstTest) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); +} + +TEST(FirstTestGroup, SecondTest) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + //FAIL("Fail me!"); +} + +int main(int argc, char* argv[]) +{ + return CommandLineTestRunner::RunAllTests(argc, argv); +} \ No newline at end of file From 1d59b19594e1acca3df07887642f42fedf8e160a Mon Sep 17 00:00:00 2001 From: Siza Date: Thu, 26 Aug 2021 22:07:48 +1200 Subject: [PATCH 13/18] Fix and refactor xml file parsing with test --- CHANGELOG.md | 2 +- package.json | 2 +- src/framework/CppUTestRunnable.ts | 35 ++++++++++++------ test/framework/CppUTestRunnable.test.ts | 48 +++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b7280ff..4dca6263 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] -## [3.7.0] - 2021-08-21 +## [3.7.0] Feature Added: CppUTest Framework Support with tests diff --git a/package.json b/package.json index bacdb30b..b26c899d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "icon": "resources/icon.png", "author": "Mate Pek", "publisher": "matepek", - "version": "3.6.26", + "version": "3.7.0", "license": "MIT", "homepage": "https://github.com/matepek/vscode-catch2-test-adapter", "repository": { diff --git a/src/framework/CppUTestRunnable.ts b/src/framework/CppUTestRunnable.ts index d2626fa0..d5a54a83 100644 --- a/src/framework/CppUTestRunnable.ts +++ b/src/framework/CppUTestRunnable.ts @@ -51,13 +51,12 @@ export class CppUTestRunnable extends AbstractRunnable { const reloadResult = new RunnableReloadResult(); - for (let i = 0; i < xml.testsuites.testsuite.length; ++i) { - const suiteName = xml.testsuites.testsuite[i].$.name; + const processTestcases = async (testsuite: any, reloadResult: RunnableReloadResult) => { + const suiteName = testsuite.$.name; + for (let i = 0; i < testsuite.testcase.length; i++) { + if (cancellationFlag.isCancellationRequested) return; - for (let j = 0; j < xml.testsuites.testsuite[i].testcase.length; j++) { - if (cancellationFlag.isCancellationRequested) return reloadResult; - - const testCase = xml.testsuites.testsuite[i].testcase[j]; + const testCase = testsuite.testcase[i]; const testName = testCase.$.name.startsWith('DISABLED_') ? testCase.$.name.substr(9) : testCase.$.name; const testNameAsId = suiteName + '.' + testCase.$.name; @@ -76,6 +75,15 @@ export class CppUTestRunnable extends AbstractRunnable { )), ); } + }; + + if (xml.testsuites !== undefined) { + for (let i = 0; i < xml.testsuites.testsuite.length; ++i) { + await processTestcases(xml.testsuites.testsuite[i], reloadResult) + .catch((err) => this._shared.log.info('Error', err)); + } + } else { + await processTestcases(xml.testsuite, reloadResult); } return reloadResult; @@ -160,15 +168,20 @@ export class CppUTestRunnable extends AbstractRunnable { .catch(err => this._shared.log.error('error creating xmls folder: ', junitXmlsFolderPath, err)); //Generate xml files const args = this.properties.prependTestListingArgs.concat(['-ojunit']); - const options = this.properties.options; - options.cwd = junitXmlsFolderPath; + const options = { cwd: junitXmlsFolderPath }; await this.properties.spawner .spawnAsync(this.properties.path, args, options, 30000) .then(() => this._shared.log.info('create cpputest xmls', this.properties.path, args, options.cwd)); //Merge xmls into single xml - await mergeFiles(cacheFile, [junitXmlsFolderPath + '/*.xml']) - .then(() => this._shared.log.info('cache xml written', cacheFile)) - .catch(err => this._shared.log.warn('combine xml cache file could not create: ', cacheFile, err)); + fs.readdir(junitXmlsFolderPath, (err, files) => { + if (files.length > 1) { + mergeFiles(cacheFile, [junitXmlsFolderPath + '/*.xml']) + .then(() => this._shared.log.info('cache xml written', cacheFile)) + .catch(err => this._shared.log.warn('combine xml cache file could not create: ', cacheFile, err)); + } else { + fs.copyFile(junitXmlsFolderPath + '/' + files[0], cacheFile); + } + }); //Delete xmls folder fs.remove(junitXmlsFolderPath) .then(() => this._shared.log.info('junit-xmls folder deleted', junitXmlsFolderPath)) diff --git a/test/framework/CppUTestRunnable.test.ts b/test/framework/CppUTestRunnable.test.ts index 46077093..c9cc9c16 100644 --- a/test/framework/CppUTestRunnable.test.ts +++ b/test/framework/CppUTestRunnable.test.ts @@ -5,6 +5,7 @@ import { CppUTestRunnable } from '../../src/framework/CppUTestRunnable'; import { RootSuite } from '../../src/RootSuite'; import { RunnableProperties } from '../../src/RunnableProperties'; import { DefaultSpawner } from '../../src/Spawner'; +import { EOL } from 'os'; /// @@ -165,4 +166,51 @@ describe(pathlib.basename(__filename), function () { } }); }); + + context('Testing _reloadFromXml', function () { + it('should reload ex.1', async function () { + const { root, runnable } = createCppUTestRunnable(); + + const testOutput: string[] = [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + ',', + ]; + const res = await runnable['_reloadFromXml'](testOutput.join(EOL), { isCancellationRequested: false }); + + const tests = [...res.tests].sort((a, b) => a.testNameAsId.localeCompare(b.testNameAsId)); + + assert.strictEqual(tests.length, 2); + + assert.strictEqual(tests[0].testNameAsId, 'FirstTestGroup.FirstTest'); + assert.strictEqual(tests[0].label, 'FirstTest'); + assert.strictEqual(tests[0].file, pathlib.normalize('/mnt/c/Users/testcppcpputestcpputest1.cpp')); + assert.strictEqual(tests[0].line, 14); + assert.strictEqual(tests[0].skipped, false); + assert.strictEqual(tests[0].getStaticEvent('1'), undefined); + assert.strictEqual(tests[1].testNameAsId, 'FirstTestGroup.SecondTest'); + assert.strictEqual(tests[1].label, 'SecondTest'); + assert.strictEqual(tests[1].file, pathlib.normalize('/mnt/c/Users/testcppcpputestcpputest1.cpp')); + assert.strictEqual(tests[1].line, 19); + assert.strictEqual(tests[1].skipped, false); + assert.strictEqual(tests[1].getStaticEvent('1'), undefined); + + assert.strictEqual(root.children.length, 1); + const suite1 = root.children[0]; + assert.strictEqual(suite1.label, 'name'); + if (suite1.type === 'suite') { + assert.strictEqual(suite1.children.length, 2); + } else { + assert.strictEqual(suite1.type, 'suite'); + } + }); + }); }); From 314ff4ecca7c436b07472a6bfd667a4009c8fb30 Mon Sep 17 00:00:00 2001 From: Siza Date: Sat, 28 Aug 2021 03:51:02 +1200 Subject: [PATCH 14/18] Add CppUTest default help regex --- src/RunnableFactory.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/RunnableFactory.ts b/src/RunnableFactory.ts index 5574d314..3dddd1e0 100644 --- a/src/RunnableFactory.ts +++ b/src/RunnableFactory.ts @@ -162,7 +162,9 @@ export class RunnableFactory { if (this._cpputest.helpRegex) this._shared.log.info('Custom regex', 'cpputest', this._cpputest.helpRegex); const cpputest = runWithHelpRes.stdout.match( - this._cpputest.helpRegex ? new RegExp(this._cpputest.helpRegex, regexFlags) : /Thanks for using CppUTest/, + this._cpputest.helpRegex + ? new RegExp(this._cpputest.helpRegex, regexFlags) + : /[-g|sg|xg|xsg groupName]... [-n|sn|xn|xsn testName].../, ); if (cpputest) { return new CppUTestRunnable( From 917b123e68301be8e2343b5f1712af61d550260d Mon Sep 17 00:00:00 2001 From: Mate Pek Date: Sat, 28 Aug 2021 20:04:31 +0200 Subject: [PATCH 15/18] update changelog --- CHANGELOG.md | 6 ++++-- test/cpp/cpputest/cpputest1.cpp | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dca6263..c07afcd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] -## [3.7.0] +## [3.6.28] -Feature Added: CppUTest Framework Support with tests +### Added + +- (experimental) CppUTest Framework Support ## [3.6.27] - 2021-08-09 diff --git a/test/cpp/cpputest/cpputest1.cpp b/test/cpp/cpputest/cpputest1.cpp index ebdf1277..1e743330 100644 --- a/test/cpp/cpputest/cpputest1.cpp +++ b/test/cpp/cpputest/cpputest1.cpp @@ -18,6 +18,12 @@ TEST(FirstTestGroup, FirstTest) } TEST(FirstTestGroup, SecondTest) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + CHECK(false); +} + +TEST(FirstTestGroup, ThirdTest) { std::this_thread::sleep_for(std::chrono::milliseconds(2000)); //FAIL("Fail me!"); From 2e022651a512e065f8f608a4415a4c1d37b14ae2 Mon Sep 17 00:00:00 2001 From: Siza Date: Wed, 1 Sep 2021 00:28:50 +1200 Subject: [PATCH 16/18] Fix lint errors --- src/framework/CppUTestRunnable.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/framework/CppUTestRunnable.ts b/src/framework/CppUTestRunnable.ts index d5a54a83..5a729916 100644 --- a/src/framework/CppUTestRunnable.ts +++ b/src/framework/CppUTestRunnable.ts @@ -51,7 +51,7 @@ export class CppUTestRunnable extends AbstractRunnable { const reloadResult = new RunnableReloadResult(); - const processTestcases = async (testsuite: any, reloadResult: RunnableReloadResult) => { + const processTestcases = async (testsuite: XmlObject, reloadResult: RunnableReloadResult): Promise => { const suiteName = testsuite.$.name; for (let i = 0; i < testsuite.testcase.length; i++) { if (cancellationFlag.isCancellationRequested) return; @@ -79,8 +79,9 @@ export class CppUTestRunnable extends AbstractRunnable { if (xml.testsuites !== undefined) { for (let i = 0; i < xml.testsuites.testsuite.length; ++i) { - await processTestcases(xml.testsuites.testsuite[i], reloadResult) - .catch((err) => this._shared.log.info('Error', err)); + await processTestcases(xml.testsuites.testsuite[i], reloadResult).catch(err => + this._shared.log.info('Error', err), + ); } } else { await processTestcases(xml.testsuite, reloadResult); @@ -201,7 +202,7 @@ export class CppUTestRunnable extends AbstractRunnable { return execParams; } - protected _getDebugParamsInner(childrenToRun: readonly Readonly[], breakOnFailure: boolean): string[] { + protected _getDebugParamsInner(childrenToRun: readonly Readonly[]): string[] { // TODO: Proper debug options // TODO: colouring 'debug.enableOutputColouring' // TODO: Add multiple options From bd3b161056f0f2a1aafb03488f8b26ed735e65db Mon Sep 17 00:00:00 2001 From: Siza Date: Fri, 3 Sep 2021 20:56:57 +1200 Subject: [PATCH 17/18] Remove unnecessary todos --- src/framework/CppUTestRunnable.ts | 4 ---- src/framework/CppUTestTest.ts | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/framework/CppUTestRunnable.ts b/src/framework/CppUTestRunnable.ts index 5a729916..54049f00 100644 --- a/src/framework/CppUTestRunnable.ts +++ b/src/framework/CppUTestRunnable.ts @@ -192,7 +192,6 @@ export class CppUTestRunnable extends AbstractRunnable { } protected _getRunParamsInner(childrenToRun: readonly Readonly[]): string[] { - // TODO: Add multiple options const execParams: string[] = []; childrenToRun.forEach(t => { execParams.push(`TEST(${t.testNameAsId.split('.')[0]}, ${t.testNameAsId.split('.')[1]})`); @@ -203,9 +202,6 @@ export class CppUTestRunnable extends AbstractRunnable { } protected _getDebugParamsInner(childrenToRun: readonly Readonly[]): string[] { - // TODO: Proper debug options - // TODO: colouring 'debug.enableOutputColouring' - // TODO: Add multiple options const execParams: string[] = []; childrenToRun.forEach(t => { execParams.push(`TEST(${t.testNameAsId.split('.')[0]}, ${t.testNameAsId.split('.')[1]})`); diff --git a/src/framework/CppUTestTest.ts b/src/framework/CppUTestTest.ts index bd38de76..80f6a9bb 100644 --- a/src/framework/CppUTestTest.ts +++ b/src/framework/CppUTestTest.ts @@ -67,7 +67,7 @@ export class CppUTestTest extends AbstractTest { this.lastRunEvent = ev; return ev; } - //TODO: Refactor following codes + try { const lines = output.split(/\r?\n/); From 9631ffe3e864db6057db3e53da43ef27ff5e524b Mon Sep 17 00:00:00 2001 From: Siza Date: Thu, 16 Mar 2023 22:23:06 +1300 Subject: [PATCH 18/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9fbf7554..6a1c47cb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # C++ TestMate -## A **Catch2**, **GoogleTest**, **CppUTest**, **doctest** and **GoogleBenchmark** Explorer for VSCode +## A **CppUTest**, **Catch2**, **GoogleTest**, **doctest** and **GoogleBenchmark** Explorer for VSCode [![Visual Studio Marketplace](https://img.shields.io/vscode-marketplace/v/matepek.vscode-catch2-test-adapter.svg)](https://marketplace.visualstudio.com/items?itemName=matepek.vscode-catch2-test-adapter) [![GitHub issues](https://img.shields.io/github/issues/matepek/vscode-catch2-test-adapter?color=green)](https://github.com/matepek/vscode-catch2-test-adapter/issues)