diff --git a/.eslintrc.json b/.eslintrc.json index 2ccc387a..43b381c2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -69,6 +69,7 @@ "warn", { "vars": "all", "args": "none", + "argsIgnorePattern": "^_", "ignoreRestSiblings": false } ], diff --git a/.gitignore b/.gitignore index 7a60c24d..d7010009 100644 --- a/.gitignore +++ b/.gitignore @@ -61,3 +61,5 @@ test_projects/proj7_load_performance/src/classes # Dowloaded test files test_projects/proj7_load_performance/v*.tar.gz test_projects/proj7_load_performance/src/ADE-* + +.worktrees/ diff --git a/.vscode/settings.json b/.vscode/settings.json index e001ae1a..b4208be3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -26,7 +26,7 @@ }, "files.exclude": { "./dist/**": true, - // "**/*{.js,.test.js}": { "when": "$(basename).ts" } + "**/.worktrees": true }, "files.watcherExclude": { ".git/objects": true, diff --git a/CHANGELOG.md b/CHANGELOG.md index 32ec037f..a093eeb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,58 +1,3 @@ -# 🥳 [1.0.0](https://github.com/kenherring/ablunit-test-runner/releases/tag/1.0.0) - 2024-10-24 - -* Finally, a non-preview release! -* Various fixes and updates -* Improved test run output, including call stacks with test failure messages - -**Full Changelog**: [0.2.0...1.0.0](https://github.com/kenherring/ablunit-test-runner/compare/0.2.17...1.0.0) - - - -# 🥇 [0.2.0](https://github.com/kenherring/ablunit-test-runner/releases/tag/0.2.0) - 2024-01-22 +# [0.2.0](https://github.com/kenherring/ablunit-test-runner/releases/tag/0.2.0) - 2024-01-22 Initial release to marketplace diff --git a/esbuild.js b/esbuild.js index d53563ab..0a0f94e8 100644 --- a/esbuild.js +++ b/esbuild.js @@ -5,7 +5,7 @@ const watch = process.argv.includes('--watch') let logtag = '[build]' if (watch) { - logtag = '[watch]' + logtag = '[watch]' } async function main () { @@ -26,7 +26,7 @@ async function main () { ] }) if (watch) { - console.log(logtag + ' watching...') + console.log(logtag + ' watching...') await ctx.watch() } else { await ctx.rebuild() @@ -47,11 +47,11 @@ const esbuildProblemMatcherPlugin = { build.onEnd(result => { result.errors.forEach(({ text, location }) => { console.error(`✘ [ERROR] ${text}`) - if (location) { - console.error(` ${location.file}:${location.line}:${location.column}:`) - } else { - console.error(' location unknown') - } + if (location) { + console.error(` ${location.file}:${location.line}:${location.column}:`) + } else { + console.error(' location unknown') + } }) console.log(logtag + ' build finished') }) diff --git a/package-lock.json b/package-lock.json index 21a9d315..49cbccdb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@types/mocha": "^9.1.1", "@types/node": "20.X", "@types/vscode": "^1.94.0", + "@types/xml2js": "^0.4.14", "@typescript-eslint/eslint-plugin": "^8.8.1", "@typescript-eslint/parser": "^8.8.1", "@vscode/test-cli": "^0.0.10", @@ -1599,6 +1600,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/xml2js": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz", + "integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.8.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz", @@ -2865,9 +2876,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 98cb475f..9aa7578f 100644 --- a/package.json +++ b/package.json @@ -101,6 +101,7 @@ "@types/mocha": "^9.1.1", "@types/node": "20.X", "@types/vscode": "^1.94.0", + "@types/xml2js": "^0.4.14", "@typescript-eslint/eslint-plugin": "^8.8.1", "@typescript-eslint/parser": "^8.8.1", "@vscode/test-cli": "^0.0.10", diff --git a/src/ABLPromsgs.ts b/src/ABLPromsgs.ts index 994ee67c..45c73a7a 100644 --- a/src/ABLPromsgs.ts +++ b/src/ABLPromsgs.ts @@ -39,8 +39,8 @@ export class ABLPromsgs { async loadPromsgFile (msgfile: Uri) { const lines = await workspace.fs.readFile(msgfile).then((buffer) => { return Buffer.from(buffer).toString('utf8').split('\n') - }, (err) => { - throw new Error('Cannot read promsgs file \'' + msgfile + '\', err=' + err) + }, (e: unknown) => { + throw new Error('Cannot read promsgs file \'' + msgfile + '\', err=' + e) }) @@ -93,10 +93,10 @@ export class ABLPromsgs { }).then(() => { log.info('promsgs loaded from DLC') return - }, (err) => { - throw new Error('Cannot read promsgs directory \'' + promsgDir + '\', err=' + err) + }, (e: unknown) => { + throw new Error('Cannot read promsgs directory \'' + promsgDir + '\', err=' + e) }) - // }, (err) => { + // }, (e: unknown) => { // log.info('Cannot find DLC directory \'' + this.dlc.uri.fsPath + '"') // throw new Error('Cannot find DLC directory \'' + this.dlc.uri.fsPath + '", err=' + err) // }) @@ -107,8 +107,8 @@ export class ABLPromsgs { await workspace.fs.readFile(cacheUri).then((buffer) => { this.promsgs = JSON.parse(Buffer.from(buffer).toString('utf8')) as IPromsg[] return - }, (err) => { - throw new Error('Cannot read promsgs file \'' + cacheUri.fsPath + '\', err=' + err) + }, (e: unknown) => { + throw new Error('Cannot read promsgs file \'' + cacheUri.fsPath + '\', err=' + e) }) } @@ -121,8 +121,8 @@ export class ABLPromsgs { return workspace.fs.writeFile(cacheUri, Buffer.from(JSON.stringify(this.promsgs, null, 2))).then(() => { log.info('saved promsgs cache successfully \'' + cacheUri.fsPath + '\'') return - }, (err) => { - throw new Error('error writing promsgs cache file: ' + err) + }, (e: unknown) => { + throw new Error('error writing promsgs cache file: ' + e) }) } @@ -152,7 +152,7 @@ export function getPromsgText (text: string) { } }) return stackString - } catch (e) { + } catch (_e) { return text } } diff --git a/src/ABLPropath.ts b/src/ABLPropath.ts index 50376699..a7052031 100644 --- a/src/ABLPropath.ts +++ b/src/ABLPropath.ts @@ -1,5 +1,5 @@ import { Uri, workspace, WorkspaceFolder } from 'vscode' -import { IProjectJson } from './parse/OpenedgeProjectParser' +import { getOpenEdgeProfileConfig, IBuildPathEntry, IProjectJson } from './parse/OpenedgeProjectParser' import { isRelativePath } from './ABLUnitCommon' import { log } from './ChannelLogger' @@ -44,6 +44,35 @@ export class PropathParser { this.buildmap = new Map() } + setPropathFromProjectJson () { + if (!workspace.workspaceFolders) { + return + } + const conf = getOpenEdgeProfileConfig(this.workspaceFolder.uri) + + if (conf && conf.buildPath.length > 0) { + const pathObj: IBuildPathEntry[] = [] + for (const e of conf.buildPath) { + pathObj.push({ + path: e.path, + type: e.type.toLowerCase(), + buildDir: e.buildDir, + xrefDir: e.xrefDir + }) + } + this.setPropath({ propathEntry: pathObj }) + } else { + this.setPropath({ propathEntry: [{ + path: '.', + type: 'source', + buildDir: '.', + xrefDir: '.' + }]}) + } + + log.info('set propath=\'' + this.toString() + '\'') + } + setPropath (importedPropath: IProjectJson) { log.debug('importedPropath.length=' + importedPropath.propathEntry.length) diff --git a/src/ABLResults.ts b/src/ABLResults.ts index 2bd57cbf..eddfdc9d 100644 --- a/src/ABLResults.ts +++ b/src/ABLResults.ts @@ -6,7 +6,7 @@ import { FileType, MarkdownString, TestItem, TestItemCollection, TestMessage, Te TestRunProfileKind} from 'vscode' import { ABLUnitConfig } from './ABLUnitConfigWriter' import { ABLResultsParser, ITestCaseFailure, ITestCase, ITestSuite } from './parse/ResultsParser' -import { ABLTestSuite, ABLTestData, ABLTestCase } from './testTree' +import { ABLTestSuite, ABLTestDir, ABLTestCase, testData, ABLTestData} from './testTree' import { parseCallstack } from './parse/CallStackParser' import { ABLProfile, ABLProfileJson, IModule } from './parse/ProfileParser' import { ABLDebugLines } from './ABLDebugLines' @@ -15,7 +15,7 @@ import { PropathParser } from './ABLPropath' import { log } from './ChannelLogger' import { ABLUnitRuntimeError, RunStatus, TimeoutError, ablunitRun } from './ABLUnitRun' import { getDLC, IDlc } from './parse/OpenedgeProjectParser' -import { Duration, isRelativePath } from './ABLUnitCommon' +import { Duration } from './ABLUnitCommon' import { ITestObj } from 'parse/config/CoreOptions' export class ABLResults implements Disposable { @@ -27,6 +27,7 @@ export class ABLResults implements Disposable { duration: Duration ablResults: ABLResultsParser | undefined tests: TestItem[] = [] + topLevelTests: ITestObj[] = [] testQueue: ITestObj[] = [] testData = new WeakMap() skippedTests: TestItem[] = [] @@ -107,22 +108,18 @@ export class ABLResults implements Disposable { const prom: (Thenable | Promise | Promise | undefined)[] = [] prom[0] = this.cfg.createProfileOptions(this.cfg.ablunitConfig.profOptsUri, this.cfg.ablunitConfig.profiler) prom[1] = this.cfg.createProgressIni(this.propath.toString(), this.dlc) - prom[2] = this.cfg.createAblunitJson(this.cfg.ablunitConfig.config_uri, this.cfg.ablunitConfig.options, this.testQueue) + // prom[2] = this.cfg.createAblunitJson(this.cfg.ablunitConfig.config_uri, this.cfg.ablunitConfig.options, this.topLevelTests) prom[3] = this.cfg.createDbConnPf(this.cfg.ablunitConfig.dbConnPfUri, this.cfg.ablunitConfig.dbConns) return Promise.all(prom).then(() => { - log.info('done creating config files for run') + log.info('done creating config files for start') return - }, (err) => { + }, (err: unknown) => { log.error('ABLResults.start() did not complete promises. err=' + err) }) } - resetTests () { - this.tests = [] - } - - async addTest (test: TestItem, data: ABLTestData, options: TestRun) { + async addTest (test: TestItem, data: ABLTestData, options: TestRun, isTopLevel: boolean) { if (!test.uri) { log.error('test.uri is undefined (test.label = ' + test.label + ')', options) return @@ -131,51 +128,116 @@ export class ABLResults implements Disposable { throw new Error('propath is undefined') } - const testPropath = await this.propath.search(test.uri) - if (!testPropath) { - this.skippedTests.push(test) - log.warn('skipping test, not found in propath: ' + workspace.asRelativePath(test.uri), options) - return + log.debug('addTest: ' + test.id + '; this.tests.length=' + this.tests.length) + if (this.tests.includes(test)) { + log.info('test already exists in tests: ' + test.id) } - let propathEntryTestFile = testPropath.propathEntry.path - if (isRelativePath(testPropath.propathEntry.path)) { - propathEntryTestFile = workspace.asRelativePath(Uri.joinPath(this.workspaceFolder.uri, testPropath.propathEntry.path)) - } - log.debug('addTest: ' + test.id + ', propathEntry=' + propathEntryTestFile) this.tests.push(test) this.testData.set(test, data) let testCase: string | undefined = undefined + if (!data) { + log.error('could not find test data for TestItem.id=' + test.id) + return + } if (data instanceof ABLTestCase) { + log.info('101 test.label=' + test.label + ' is a test case') testCase = test.label } const testUri = test.uri let testRel: string = workspace.asRelativePath(testUri, false) + log.info('102 testRel=' + testRel) const p = await this.propath.search(testUri) + if (!p?.propathRelativeFile) { + if (data instanceof ABLTestDir) { + log.info('directory ' + testRel + ' not found in propath, adding children') + for (const [ , child ] of test.children) { + await this.addTest(child, data, options, isTopLevel) + } + return + } else { + log.warn('test file ' + testRel + ' not found in propath') + return + } + } testRel = (p?.propathRelativeFile ?? testRel).replace(/\\/g, '/') - const testObj: ITestObj = { test: testRel } - if (testCase) { - testObj.cases = [ testCase ] + log.info('103.1') + let testObj: ITestObj | undefined = undefined + log.info('103.2') + log.info('103.3 ' + JSON.stringify(data)) + log.info('104.4 ' + typeof data) + log.info('103.5 ' + data.label) + log.info('103.6 ' + data.type) + if (data instanceof ABLTestDir) { + // testObj = { folder: workspace.asRelativePath(testUri, false) } + testObj = { folder: p?.uri.fsPath.replace(/\\/g, '/') ?? workspace.asRelativePath(test.uri) } + } else { + testObj = { test: testRel } + if (testCase) { + testObj.cases = [ testCase ] + } } - const existingTestObj = this.testQueue.find((t: ITestObj) => t.test === testRel) - if (testCase && existingTestObj) { - if(testObj.cases) { - if (!existingTestObj.cases) { - existingTestObj.cases = [] + if (isTopLevel) { + if (testObj.folder) { + log.info('folder = ' + testObj.folder) + const existing = this.topLevelTests.find((exist) => testObj.folder === exist.folder) + log.info('existing = ' + JSON.stringify(existing)) + if (existing) { + log.warn('test dir already added to test run queue: ' + testObj.folder) + } else { + this.topLevelTests.push(testObj) } - existingTestObj.cases.push(testCase) + } else { + this.topLevelTests.push(testObj) } - return } + log.info('104') + if (testObj.test && testCase) { + log.info('105') + const existingTestObj = this.testQueue.find((t: ITestObj) => t.test === testRel) + if (existingTestObj) { + if(testObj.cases) { + if (!existingTestObj.cases) { + existingTestObj.cases = [] + } + log.info('106') + existingTestObj.cases.push(testCase) + } + return + } + // } + // if (isTopLevel) { + // if (!this.topLevelTests.find((exist) => exist.test == testObj.test && exist.cases == testObj.cases)) { + // this.topLevelTests.push(testObj) + // } + // } + // return + } + + log.info('107 ' + JSON.stringify(testObj)) if (this.testQueue.find((t: ITestObj) => t.test === testRel)) { log.warn('test already exists in configJson.tests: ' + testRel) + return } else { - this.testQueue.push(testObj) + log.info('108') + if (testObj.folder) { + if (this.testQueue.find((t: ITestObj) => t.folder === testObj.folder)) { + this.testQueue.push(testObj) + } + } + // if (isTopLevel) { + // log.info('109 this.topLevelTests.length=' + this.topLevelTests.length + '; ' + JSON.stringify(testObj)) + // if (this.tests || !this.topLevelTests.find((exist) => testObj.test == exist.test)) { + // if (!this.topLevelTests.includes(testObj)) { + // if (this.topLevelTests.find((exist) => testObj.folder == exist.folder)) { + // this.topLevelTests.push(testObj) + // } + // } } } @@ -232,10 +294,10 @@ export class ABLResults implements Disposable { throw new Error('No results found in ' + this.cfg.ablunitConfig.optionsUri.filenameUri.fsPath + '\r\n') } return true - }, (err) => { + }, (e: unknown) => { this.setStatus(RunStatus.Error, 'parsing results') - log.error('Error parsing results from ' + this.cfg.ablunitConfig.optionsUri.filenameUri.fsPath + '. err=' + err, options) - throw new Error('Error parsing results from ' + this.cfg.ablunitConfig.optionsUri.filenameUri.fsPath + '\r\nerr=' + err) + log.error('Error parsing results from ' + this.cfg.ablunitConfig.optionsUri.filenameUri.fsPath + '. err=' + e, options) + throw new Error('Error parsing results from ' + this.cfg.ablunitConfig.optionsUri.filenameUri.fsPath + '\r\nerr=' + e) }) if (this.request.profile?.kind === TestRunProfileKind.Coverage && this.cfg.ablunitConfig.profiler.enabled && this.cfg.ablunitConfig.profiler.coverage) { @@ -244,10 +306,10 @@ export class ABLResults implements Disposable { await this.parseProfile().then(() => { log.info('parsing profiler data complete ' + parseTime.toString()) return true - }, (err) => { + }, (e: unknown) => { this.setStatus(RunStatus.Error, 'profiler data') - log.error('Error parsing profiler data from ' + this.cfg.ablunitConfig.profFilenameUri.fsPath + '. err=' + err, options) - throw new Error('Error parsing profiler data from ' + workspace.asRelativePath(this.cfg.ablunitConfig.profFilenameUri) + '\r\nerr=' + err) + log.error('Error parsing profiler data from ' + this.cfg.ablunitConfig.profFilenameUri.fsPath + '. err=' + e, options) + throw new Error('Error parsing profiler data from ' + workspace.asRelativePath(this.cfg.ablunitConfig.profFilenameUri) + '\r\nerr=' + e) }) } @@ -256,7 +318,14 @@ export class ABLResults implements Disposable { } async assignTestResults (item: TestItem, options: TestRun) { - + const itemData = testData.get(item) + if (itemData instanceof ABLTestDir) { + log.debug('assigning test results for children of directory: ' + item.label) + for (const [ , child ] of item.children) { + await this.assignTestResults(child, options) + } + return + } if (this.skippedTests.includes(item)) { options.skipped(item) return @@ -280,12 +349,15 @@ export class ABLResults implements Disposable { const suiteName = await this.getSuiteName(item) const s = this.ablResults.resultsJson[0].testsuite.find((s: ITestSuite) => s.classname === suiteName || s.name === suiteName) if (!s) { + log.info('400') log.error('could not find test suite for \'' + suiteName + '\' in results (item=' + item.label + ')') + log.info('401') options.errored(item, new TestMessage('could not find test suite for \'' + suiteName + '\' in results'), this.duration.elapsed()) + log.info('402') return } - const data = this.testData.get(item) + const data = testData.get(item) if (data instanceof ABLTestSuite) { if (!s.testsuite) { log.error('no child testsuites found (item=' + item.label + ')') @@ -459,8 +531,8 @@ export class ABLResults implements Disposable { .then(() => { log.debug('assignProfileResults complete (time=' + (Number(new Date()) - Number(startTime)) + ')') return - }, (err) => { - throw new Error('assignProfileResults error: ' + err) + }, (e: unknown) => { + throw new Error('assignProfileResults error: ' + e) }) } diff --git a/src/ABLUnitRun.ts b/src/ABLUnitRun.ts index 429608f4..11214338 100644 --- a/src/ABLUnitRun.ts +++ b/src/ABLUnitRun.ts @@ -84,7 +84,7 @@ export const ablunitRun = async (options: TestRun, res: ABLResults, cancellation throw new CancellationError() }) - await res.cfg.createAblunitJson(res.cfg.ablunitConfig.config_uri, res.cfg.ablunitConfig.options, res.testQueue) + await res.cfg.createAblunitJson(res.cfg.ablunitConfig.config_uri, res.cfg.ablunitConfig.options, res.topLevelTests) const getCommand = () => { if (res.cfg.ablunitConfig.command.executable != '_progres' && diff --git a/src/extension.ts b/src/extension.ts index ba315241..a22f3851 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -25,6 +25,7 @@ import { ABLTestCase, ABLTestClass, ABLTestData, ABLTestDir, ABLTestFile, ABLTes import { minimatch } from 'minimatch' import { ABLUnitRuntimeError, TimeoutError } from 'ABLUnitRun' import { basename } from 'path' +import { PropathParser } from 'ABLPropath' export interface IExtensionTestReferences { testController: TestController @@ -34,6 +35,7 @@ export interface IExtensionTestReferences { let recentResults: ABLResults[] = [] let recentError: Error | undefined = undefined +const propathMap = new Map() export async function activate (context: ExtensionContext) { const ctrl = tests.createTestController('ablunitTestController', 'ABLUnit Test') @@ -144,17 +146,29 @@ export async function activate (context: ExtensionContext) { return window.showTextDocument(Uri.joinPath(workspaceFolder.uri, '.vscode', 'ablunit-test-profile.json')).then(() => { log.info('Opened .vscode/ablunit-test-profile.json') return - }, (err) => { - log.error('Failed to open .vscode/ablunit-test-profile.json! err=' + err) + }, (e: unknown) => { + log.error('Failed to open .vscode/ablunit-test-profile.json! err=' + e) return }) } const startTestRun = (request: TestRunRequest, cancellation: CancellationToken) => { recentResults = [] + const topLevelTests: TestItem[] = [] - const discoverTests = async (tests: Iterable) => { + + const enqueueTestsAndChildren = (tests: TestItemCollection) => { + for(const [, test ] of tests) { + run.enqueued(test) + enqueueTestsAndChildren(test.children) + } + } + + const discoverTests = async (tests: Iterable, isTopLevel: boolean) => { for (const test of tests) { + if (isTopLevel) { + topLevelTests.push(test) + } if (run.token.isCancellationRequested) { return } @@ -163,17 +177,21 @@ export async function activate (context: ExtensionContext) { } const data = testData.get(test) + log.info('300 ' + test.id) - if (data instanceof ABLTestFile || data instanceof ABLTestCase) { + if (data instanceof ABLTestFile || data instanceof ABLTestCase || data instanceof ABLTestDir) { run.enqueued(test) + enqueueTestsAndChildren(test.children) + log.info('queue.push(' + test.id + ')') + log.info('push') queue.push({ test, data }) - for(const [,childTest] of test.children) { - run.enqueued(childTest) + if (data instanceof ABLTestDir) { + await discoverTests(gatherTestItems(test.children), isTopLevel) } } else { - await discoverTests(gatherTestItems(test.children)) + await discoverTests(gatherTestItems(test.children), test.id.endsWith('#ABLTestSuiteGroup')) } } } @@ -250,18 +268,28 @@ export async function activate (context: ExtensionContext) { log.debug('cannot print totals - missing ablResults object') } + log.info('500.1') for (const { test } of queue) { - if (workspace.getWorkspaceFolder(test.uri!) === r.workspaceFolder) { + log.info('500.2') + if (test.uri && workspace.getWorkspaceFolder(test.uri) === r.workspaceFolder) { + log.info('500.3') if (run.token.isCancellationRequested) { + log.info('500.4') log.debug('cancellation requested - runTestQueue-2') throw new CancellationError() } else { + log.info('500.5') await r.assignTestResults(test, run) + log.info('500.6') } + log.info('500.7') } + log.info('500.8') } + log.info('501') } + log.info('502') if(!ret) { for (const { test } of queue) { run.errored(test, new TestMessage('ablunit run failed')) @@ -272,6 +300,7 @@ export async function activate (context: ExtensionContext) { run.end() return } + log.info('503') log.debug('ablunit test run complete', run) @@ -307,19 +336,38 @@ export async function activate (context: ExtensionContext) { const createABLResults = async () => { const res: ABLResults[] = [] + log.info('200') for(const {test, data } of queue) { + log.info('201') + log.info('test.id=' + test.id) if (run.token.isCancellationRequested) { return } - const wf = workspace.getWorkspaceFolder(test.uri!) + log.info('202 test.uri=' + test.uri) + + let wf: WorkspaceFolder | undefined = undefined + if (test.uri) { + wf = workspace.getWorkspaceFolder(test.uri) + } + log.info('203 wf=' + wf) if (!wf) { - log.error('Skipping test run for test item with no workspace folder: ' + test.uri!.fsPath) + if (test.id.endsWith('#ABLTestSuiteGroup')) { + log.info('Skip add for ABLTestSuiteGroup (children added separately)') + } else { + log.info('204') + log.error('Skipping test run for test item with no workspace folder: ' + test.uri?.fsPath) + log.info('205') + } continue } + log.info('206') let r = res.find(r => r.workspaceFolder === wf) + log.info('207') if (!r) { + log.info('208') r = new ABLResults(wf, await getStorageUri(wf), contextStorageUri, contextResourcesUri, request, cancellation) + log.info('209') cancellation.onCancellationRequested(() => { log.debug('cancellation requested - createABLResults-1') r?.dispose() @@ -328,18 +376,18 @@ export async function activate (context: ExtensionContext) { await r.start() res.push(r) } - if (!data.didResolve) { - if (!test.uri) { - log.warn('cannot resolve test item with no uri: ' + test.id) - } else { - await updateNode(test.uri, ctrl) - } - } - await r.addTest(test, data, run) + log.info('210') + await r.addTest(test, data, run, topLevelTests.includes(test) || data instanceof ABLTestDir) + log.info('211') } + log.info('212') resultData.set(run, res) + log.info('213') log.debug('all tests added to test run results object, preparing test run ' + res[0].duration.toString()) + log.info('214') + log.info('all tests added to test run results object, preparing test run ' + res[0].duration.toString()) + log.info('215') return res } @@ -355,7 +403,7 @@ export async function activate (context: ExtensionContext) { }) const tests = request.include ?? gatherTestItems(ctrl.items) - return discoverTests(tests) + return discoverTests(tests, true) .then(() => { return createABLResults() }) .then((res) => { if (!res) { @@ -391,7 +439,9 @@ export async function activate (context: ExtensionContext) { log.info('skipping updateNodeForDocument for file not in workspace: ' + u.fsPath) return Promise.resolve(false) } + log.info('550') return updateNode(u, ctrl) + .then(() => { log.info('551'); return }) } function resolveHandlerFunc (item: TestItem | undefined) { @@ -402,8 +452,8 @@ export async function activate (context: ExtensionContext) { return commands.executeCommand('testing.refreshTests').then(() => { log.trace('tests tree successfully refreshed on workspace startup') return - }, (err) => { - log.error('failed to refresh test tree. err=' + err) + }, (e: unknown) => { + log.error('failed to refresh test tree. err=' + e) }) } return Promise.resolve() @@ -417,7 +467,7 @@ export async function activate (context: ExtensionContext) { const data = testData.get(item) if (data instanceof ABLTestFile) { - return data.updateFromDisk(ctrl, item).then(() => { return }, (err) => { throw err }) + return data.updateFromDisk(ctrl, item).then(() => { return }, (e: unknown) => { throw e }) } return Promise.resolve() } @@ -426,15 +476,11 @@ export async function activate (context: ExtensionContext) { log.info('ctrl.refreshHandler start') isRefreshTestsComplete = false return refreshTestTree(ctrl, token) - .then((r) => { - log.info('ctrl.refreshHandler post-refreshTestTree (r=' + r + ')') - isRefreshTestsComplete = true - return - }, (e) => { throw e }) + .then((r) => { isRefreshTestsComplete = true; return }) + .catch((e: unknown) => { throw e }) } - ctrl.resolveHandler = (item) => { - + ctrl.resolveHandler = item => { if (item?.uri) { const relativePath = workspace.asRelativePath(item.uri) log.info('ctrl.resolveHandler (relativePath=' + relativePath + ')') @@ -456,7 +502,7 @@ export async function activate (context: ExtensionContext) { .then(() => { log.info('tests tree successfully refreshed on configuration change') return - }, (e) => { + }, (e: unknown) => { throw e }) } @@ -489,21 +535,23 @@ let contextStorageUri: Uri let contextResourcesUri: Uri let contextLogUri: Uri -function updateNode (uri: Uri, ctrl: TestController) { - log.debug('updateNode uri="' + uri.fsPath + '"') +async function updateNode (uri: Uri, ctrl: TestController) { + log.trace('updateNode uri=' + uri.fsPath) if(uri.scheme !== 'file' || isFileExcluded(uri, getWorkspaceTestPatterns()[1])) { return Promise.resolve(false) } const { item, data } = getOrCreateFile(ctrl, uri) if(!item || !data) { - return Promise.resolve(false) + return new Promise(() => { return false }) } ctrl.invalidateTestResults(item) - return getContentFromFilesystem(uri).then((contents) => { - log.debug('updateFromContents item.id=' + item.id) - return data.updateFromContents(ctrl, contents, item) + await getContentFromFilesystem(uri).then((contents) => { + data.updateFromContents(ctrl, contents, item) + return + }, (e: unknown) => { + throw e }) } @@ -572,6 +620,39 @@ function getOrCreateFile (controller: TestController, uri: Uri, excludePatterns? return { item: undefined, data: undefined } } + const wf = workspace.getWorkspaceFolder(uri) + log.info('wf=' + wf) + if (!wf) { + throw new Error('workspace folder not found for uri: ' + uri.fsPath) + } + let p = propathMap.get(wf.uri.fsPath) + log.info('p=' + p) + if (!p) { + p = new PropathParser(wf) + p.setPropathFromProjectJson() + log.info('p(2)=' + p) + if (!p) { + log.warn('unable to create propath for workspace folder: ' + wf.uri.fsPath) + if (existing) { + deleteTest(controller, existing) + } + return { item: undefined, data: undefined } + } + propathMap.set(wf.uri.fsPath, p) + return { item: undefined, data: undefined } + } + // log.info('propath=' + JSON.stringify(p.getPropath())) + // const pEntry = await p.search(uri) + // log.info('pEntry=' + JSON.stringify(pEntry)) + // if (!pEntry) { + // log.info('no propath entry found for uri: ' + uri.fsPath) + // if (existing) { + // deleteTest(controller, existing) + // } + // return { item: undefined, data: undefined } + // } + + if (existing) { const data = testData.get(existing) if (!data) { @@ -591,7 +672,7 @@ function getOrCreateFile (controller: TestController, uri: Uri, excludePatterns? const data = createFileNode(uri) if(!data) { - log.trace('No tests found in file: ' +workspace.asRelativePath(uri)) + log.trace('No tests found in file: ' + workspace.asRelativePath(uri)) return { item: undefined, data: undefined } } const file = controller.createTestItem(uri.fsPath, basename(uri.fsPath), uri) @@ -600,7 +681,6 @@ function getOrCreateFile (controller: TestController, uri: Uri, excludePatterns? file.description = 'To be parsed...' if (file.label.endsWith('.cls')) { file.description = 'ABL Test Class' - // TODO convert file.label to proper class name format } else if (file.label.endsWith('.p')) { file.description = 'ABL Test Program' } @@ -629,7 +709,7 @@ function getWorkspaceFolderNode (controller: TestController, workspaceFolder: Wo wf.tags = [ new TestTag('runnable'), new TestTag('ABLTestDir') ] controller.items.add(wf) - testData.set(wf, new ABLTestDir('WorkspaceFolder', workspaceFolder.name, workspaceFolder.uri)) + testData.set(wf, new ABLTestDir('WorkspaceFolder', workspaceFolder.name, workspaceFolder.uri, 'ABLTestDir')) return wf } @@ -651,7 +731,7 @@ function getTestSuiteNode (controller: TestController, workspaceFolder: Workspac suiteGroup.canResolveChildren = false suiteGroup.description = 'ABLTestSuiteGroup' suiteGroup.tags = [ new TestTag('runnable'), new TestTag('ABLTestSuiteGroup') ] - testData.set(suiteGroup, new ABLTestDir('TestSuiteGroup', '[ABL Test Suites]', groupId)) + testData.set(suiteGroup, new ABLTestDir('TestSuiteGroup', '[ABL Test Suites]', groupId, 'ABLTestDir')) siblings.add(suiteGroup) return suiteGroup @@ -694,7 +774,7 @@ function getOrCreateDirNodeForFile (controller: TestController, file: Uri, isTes dirNode.description = 'ABLTestDir' dirNode.tags = [ new TestTag('runnable'), new TestTag('ABLTestDir') ] - const data = new ABLTestDir('ABLTestDir', path, dirNode.uri!) + const data = new ABLTestDir('ABLTestDir', path, dirNode.uri!, 'ABLTestDir') testData.set(dirNode, data) siblings.add(dirNode) parent = dirNode @@ -895,14 +975,14 @@ function findMatchingFiles (includePatterns: RelativePattern[], token: Cancellat .then((files) => { filelist.push(...files) return true - }, (e) => { throw e }) + }, (e: unknown) => { throw e }) proms.push(prom) checkCancellationToken() } return Promise.all(proms) .then(() => { return filelist - }, (e) => { throw e }) + }, (e: unknown) => { throw e }) } // async function parseMatchingFiles (files: Uri[], controller: TestController, excludePatterns: RelativePattern[], token: CancellationToken, checkCancellationToken: () => void): Promise { @@ -937,7 +1017,7 @@ function removeDeletedFiles (ctrl: TestController) { .then((s) => { log.debug('file still exists, skipping delete (item.id=' + item.id + ')') return - }, (e) => { + }, (e: unknown) => { deleteTest(ctrl, item) }) proms.push(p) @@ -1057,26 +1137,6 @@ function createOrUpdateFile (controller: TestController, e: Uri | FileCreateEven return Promise.all(proms).then(() => { return true }) } -// function startWatchingWorkspace (controller: TestController) { -// log.info('start watching workspace') -// const [ includePatterns, excludePatterns ] = getWorkspaceTestPatterns() -// log.debug('includePatterns=' + includePatterns.length + ', excludePatterns=' + excludePatterns.length) - -// const watchers: FileSystemWatcher[] = [] - -// // TODO - different patterns in different workspaces... - -// for (const includePattern of includePatterns) { -// log.info('creating watcher for: ' + includePattern.pattern) -// const watcher = workspace.createFileSystemWatcher(includePattern) -// watcher.onDidCreate(uri => { log.info('watcher.onDidCreate'); return createOrUpdateFile(controller, uri, true) }) -// watcher.onDidChange(uri => { log.info('watcher.onDidChange'); return createOrUpdateFile(controller, uri, true) }) -// watcher.onDidDelete(uri => { log.info('watcher.onDidDelete'); return deleteTest(controller, uri) }) -// watchers.push(watcher) -// } -// return watchers -// } - function openCallStackItem (traceUriStr: string) { const traceUri = Uri.file(traceUriStr.split('&')[0]) const traceLine = Number(traceUriStr.split('&')[1]) @@ -1088,7 +1148,7 @@ function openCallStackItem (traceUriStr: string) { log.info('decorating editor - openCallStackItem') editor.revealRange(range) return - }, (e) => { throw e }) + }, (e: unknown) => { throw e }) } function isFileIncluded (uri: Uri, includePatterns: RelativePattern[], excludePatterns: RelativePattern[]) { @@ -1135,8 +1195,8 @@ export async function doesDirExist (uri: Uri) { return true } return false - }, (err) => { - log.debug('caught: ' + err) + }, (e: unknown) => { + log.debug('caught: ' + e) return false }) return ret @@ -1148,8 +1208,8 @@ export async function doesFileExist (uri: Uri) { return true } return false - }, (err) => { - log.debug('caught: ' + err) + }, (e: unknown) => { + log.debug('caught: ' + e) return false }) return ret diff --git a/src/parse/ProfileParser.ts b/src/parse/ProfileParser.ts index c988e3c0..5632e57e 100644 --- a/src/parse/ProfileParser.ts +++ b/src/parse/ProfileParser.ts @@ -86,8 +86,8 @@ export class ABLProfile { return workspace.fs.writeFile(uri, Uint8Array.from(Buffer.from(JSON.stringify(data, null, 2)))).then(() => { log.info('wrote profile output json file: ' + workspace.asRelativePath(uri)) return - }, (err) => { - log.error('failed to write profile output json file ' + workspace.asRelativePath(uri) + ' - ' + err) + }, (e: unknown) => { + log.error('failed to write profile output json file ' + workspace.asRelativePath(uri) + ' - ' + e) }) } } diff --git a/src/parse/ResultsParser.ts b/src/parse/ResultsParser.ts index 33c4df84..1c82fe76 100644 --- a/src/parse/ResultsParser.ts +++ b/src/parse/ResultsParser.ts @@ -92,7 +92,8 @@ export class ABLResultsParser { parseXml (xmlData: string): string { let res: string | undefined - parseString(xmlData, function (e: Error | null, resultsRaw: unknown) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + parseString(xmlData, (e: Error | null, resultsRaw: unknown) => { if (e) { log.info('error parsing XML file: ' + e) throw e @@ -281,8 +282,8 @@ export class ABLResultsParser { return workspace.fs.writeFile(uri, Uint8Array.from(Buffer.from(JSON.stringify(data, null, 2)))).then(() => { log.info('wrote results json file: ' + uri.fsPath) return - }, (err) => { - log.error('failed to write profile output json file ' + uri.fsPath + ' - ' + err) + }, (e: unknown) => { + log.error('failed to write profile output json file ' + uri.fsPath + ' - ' + e) }) } } diff --git a/src/parse/SourceParser.ts b/src/parse/SourceParser.ts index c3987c38..fb45d4ee 100644 --- a/src/parse/SourceParser.ts +++ b/src/parse/SourceParser.ts @@ -32,9 +32,9 @@ function readXrefFile (xrefUri: Uri) { return workspace.fs.readFile(xrefUri).then((content) => { const str = Buffer.from(content.buffer).toString() return str - }, (err) => { + }, (e: unknown) => { log.trace('xref file not found \'' + xrefUri.fsPath + '\'') - log.trace(' -- err=' + err) + log.trace(' -- err=' + e) return undefined // don't rethrow, just return undefined because we don't want to stop processing }) } @@ -170,7 +170,7 @@ export const getSourceMapFromSource = (propath: PropathParser, debugSourceName: } try { debugLines = await importDebugLines(debugSourceName, fileinfo.uri, fileinfo.xrefUri) - } catch (e) { + } catch (_e: unknown) { log.warn('cannot read: ' + fileinfo.uri.fsPath) return undefined } diff --git a/src/parse/TestParserCommon.ts b/src/parse/TestParserCommon.ts index 2631b48c..9926c6c6 100644 --- a/src/parse/TestParserCommon.ts +++ b/src/parse/TestParserCommon.ts @@ -31,7 +31,7 @@ export function getContentFromFilesystem (uri: Uri | string) { uri = toUri(uri) return workspace.fs.readFile(uri) .then((rawContent) => { return textDecoder.decode(rawContent) }, - (e) => { throw e }) + (e: unknown) => { throw e }) } export function readLinesFromFile (uri: Uri | string) { diff --git a/src/parse/config/CoreOptions.ts b/src/parse/config/CoreOptions.ts index 442ce03e..f0bbcb40 100644 --- a/src/parse/config/CoreOptions.ts +++ b/src/parse/config/CoreOptions.ts @@ -1,5 +1,6 @@ export interface ITestObj { - test: string + folder?: string + test?: string cases?: string[] } diff --git a/src/testTree.ts b/src/testTree.ts index 6339bd99..842d777f 100644 --- a/src/testTree.ts +++ b/src/testTree.ts @@ -55,6 +55,7 @@ function createTestItem ( } interface ITestType { + type: string isFile: boolean didResolve: boolean runnable: boolean @@ -62,7 +63,10 @@ interface ITestType { description: string } +type TestReferenceType = 'ABLTestDir' | 'ABLTestFile' | 'ABLTestCase' | 'ABLTestClass' | 'ABLTestProgram' | 'ABLTestSuite' + class TestTypeObj implements ITestType { + public type: TestReferenceType public isFile = false public didResolve = false public runnable = false @@ -70,13 +74,15 @@ class TestTypeObj implements ITestType { public description: string public label: string - constructor (description: string, label: string) { + constructor (description: string, label: string, type: TestReferenceType) { this.description = description this.label = label + this.type = type } } export class ABLTestDir implements ITestType { + public type: TestReferenceType public isFile = false public didResolve = true public runnable = true @@ -85,7 +91,7 @@ export class ABLTestDir implements ITestType { public relativePath: string public label = '' - constructor (desc: string, label: string, path: Uri | string) { + constructor (desc: string, label: string, path: Uri | string, type: TestReferenceType) { this.description = desc this.label = label if (path instanceof Uri) { @@ -93,6 +99,12 @@ export class ABLTestDir implements ITestType { } else { this.relativePath = path } + + this.isFile = false + this.didResolve = true + this.runnable = true + this.canResolveChildren = false + this.type = type } } @@ -100,7 +112,7 @@ export class ABLTestCase extends TestTypeObj { constructor ( public readonly id: string, label: string, - description: string) { super(description, label) } + description: string) { super(description, label, 'ABLTestCase') } } export class ABLTestFile extends TestTypeObj { @@ -126,7 +138,7 @@ export class ABLTestFile extends TestTypeObj { item.error = undefined item.canResolveChildren = true return this.updateFromContents(controller, content, item) - }, (e) => { + }, (e: unknown) => { item.error = (e as Error).stack throw e }) @@ -247,7 +259,7 @@ export class ABLTestFile extends TestTypeObj { export class ABLTestSuite extends ABLTestFile { constructor (label: string) { - super('ABL Test Suite', label) + super('ABL Test Suite', label, 'ABLTestSuite') } public override updateFromContents (controller: TestController, content: string, item: TestItem) { @@ -314,7 +326,7 @@ export class ABLTestClass extends ABLTestFile { public classTypeName = '' constructor (label: string) { - super('ABL Test Class', label) + super('ABL Test Class', label, 'ABLTestClass') } setClassInfo (classTypeName?: string) { @@ -336,7 +348,7 @@ export class ABLTestClass extends ABLTestFile { export class ABLTestProgram extends ABLTestFile { constructor (label: string) { - super('ABL Test Program', label) + super('ABL Test Program', label, 'ABLTestProgram') } public override updateFromContents (controller: TestController, content: string, item: TestItem) { diff --git a/test/openedgeAblCommands.ts b/test/openedgeAblCommands.ts index 6ba93a85..fc7c51fd 100644 --- a/test/openedgeAblCommands.ts +++ b/test/openedgeAblCommands.ts @@ -51,7 +51,7 @@ export function rebuildAblProject () { const rcodeCount = getRcodeCount() log.info('abl.project.rebuild command complete! (rcodeCount=' + rcodeCount + ')') return rcodeCount - }, (err) => { throw err }) + }, (e: unknown) => { throw e }) } export async function printLastLangServerError () { diff --git a/test/parse/TestProfileParser.test.ts b/test/parse/TestProfileParser.test.ts index 6017ab75..1fdf2874 100644 --- a/test/parse/TestProfileParser.test.ts +++ b/test/parse/TestProfileParser.test.ts @@ -10,9 +10,9 @@ function readValidationFile (filename: string) { // const data = Buffer.from(content.buffer).toString().trim().replace(/[\r\t\n]/g, '').replace(/\/\/.*/g, '').replace(/^$/g, '') const conf: IConfigurations = JSON.parse(data) as IConfigurations return conf.configurations - }, (err) => { - log.error('Reading validation file failed: ' + err) - throw err + }, (e: unknown) => { + log.error('Reading validation file failed: ' + e) + throw e }) } diff --git a/test/suites/DebugLines.test.ts b/test/suites/DebugLines.test.ts index 414844c6..b425d795 100644 --- a/test/suites/DebugLines.test.ts +++ b/test/suites/DebugLines.test.ts @@ -13,7 +13,7 @@ suite('debugLines - Debug Line Tests - insiders', () => { .then((rcodeCount) => { log.info('rcodeCount=' + rcodeCount) return rcodeCount - }, (e) => { + }, (e: unknown) => { log.error('rcode error: ' + e) throw e }) diff --git a/test/suites/proj0.test.ts b/test/suites/proj0.test.ts index fdf5c6ae..d38c4eda 100644 --- a/test/suites/proj0.test.ts +++ b/test/suites/proj0.test.ts @@ -60,8 +60,8 @@ suite('proj0 - Extension Test Suite', () => { }) // is it possible to validate the line coverage displayed and not just the reported coverage? does it matter? - test('proj0.03 - open file, run test, validate coverage displays', async () => { - const testFileUri = Uri.joinPath(workspace.workspaceFolders![0].uri, 'src', 'dirA', 'dir1', 'testInDir.p') + test.skip('proj0.3 - open file, run test, validate coverage displays', async () => { + const testFileUri = toUri('src/dirA/dir1/testInDir.p') await window.showTextDocument(testFileUri) await runAllTestsWithCoverage() @@ -130,12 +130,12 @@ suite('proj0 - Extension Test Suite', () => { assert.equal(testClassItem.children.size, 5, 'testClassItem.children.size should be 5') }) - test('proj0.09 - ABLResultsParser', async () => { + test('proj0.9 - ABLResultsParser', () => { const rp = new ABLResultsParser() - await rp.parseResults(toUri('results_test1.xml')) + return rp.parseResults(toUri('results_test1.xml')) .then(() => { log.info('parsed results_test1.xml successfully') - return true + return }, (e: unknown) => { if (e instanceof Error) { log.info('e.message=' + e.message) @@ -184,7 +184,7 @@ suite('proj0 - Extension Test Suite', () => { .then((r) => { log.info('opened file (r=' + r + ')') return sleep2(250) - }, (e) => { throw e }) + }, (e: unknown) => { throw e }) const startCount = await getTestItem(toUri('src/dirA/proj10.p')) .then((r) => { @@ -192,7 +192,7 @@ suite('proj0 - Extension Test Suite', () => { log.info('c.label=' + c.label + '; c.id=' + c.id) } return r.children.size - }, (e) => { throw e }) + }, (e:unknown) => { throw e }) // update test program @@ -209,7 +209,7 @@ suite('proj0 - Extension Test Suite', () => { log.info('c.label=' + c.label + '; c.id=' + c.id) } return r.children.size - }, (e) => { throw e }) + }, (e: unknown) => { throw e }) assert.equal(endCount - startCount, 2, 'test cases added != 2 (endCount=' + endCount + '; startCount=' + startCount + ')') }) diff --git a/test/suites/proj7B.test.ts b/test/suites/proj7B.test.ts index 56dfa4eb..972b74aa 100644 --- a/test/suites/proj7B.test.ts +++ b/test/suites/proj7B.test.ts @@ -37,9 +37,9 @@ suite('proj7B - Extension Test Suite', () => { await commands.executeCommand('testing.cancelTestRefresh').then(() => { log.info('testing.cancelTestRefresh completed') return - }, (err) => { - log.error('testing.cancelTestRefresh caught an exception. err=' + err) - throw err + }, (e: unknown) => { + log.error('testing.cancelTestRefresh caught an exception. err=' + e) + throw e }) log.info(' - elapsedCancelTime=' + startCancelTime.elapsed() + 'ms, elapsedRefreshTime=' + startRefreshTime.elapsed() + 'ms') assert.durationMoreThan(startCancelTime, minCancelTime) @@ -56,12 +56,12 @@ suite('proj7B - Extension Test Suite', () => { await refresh.then(() => { assert.fail('testing.refreshTests completed without throwing CancellationError') return - }, (err) => { - if (err instanceof CancellationError) { + }, (e: unknown) => { + if (e instanceof CancellationError) { log.info('testing.refreshTests threw CancellationError as expected') } else { - const e = err as Error - assert.equal(e.name, 'Canceled', 'testing.refreshTests threw unexpected error. Expected e.name="Canceled" err=' + err) + const err = e as Error + assert.equal(err.name, 'Canceled', 'testing.refreshTests threw unexpected error. Expected e.name="Canceled" err=' + err) } }) }) diff --git a/test/suites/proj9.test.ts b/test/suites/proj9.test.ts index 906a9dea..9503e404 100644 --- a/test/suites/proj9.test.ts +++ b/test/suites/proj9.test.ts @@ -43,18 +43,9 @@ suite('proj9 - Extension Test Suite', () => { test('proj9.1 - ${workspaceFolder}/ablunit.json file exists', async () => { await runAllTests() - const workspaceFolder = workspace.workspaceFolders![0].uri - const ablunitJson = Uri.joinPath(workspaceFolder, 'ablunit.json') - const resultsXml = Uri.joinPath(workspaceFolder, 'results.xml') - const resultsJson = Uri.joinPath(workspaceFolder, 'results.json') - - assert.fileExists(ablunitJson) - assert.fileExists(resultsXml) - assert.fileExists(resultsJson) - - assert.equal(await getTestCount(resultsJson, 'pass'), 7, 'passed test count') - assert.equal(await getTestCount(resultsJson, 'fail'), 0, 'failed test count') - assert.equal(await getTestCount(resultsJson, 'error'), 0, 'error test count') + assert.tests.passed(14) + assert.tests.failed(0) + assert.tests.errored(0) }) test('proj9.2 - second profile passes (project)', async () => { diff --git a/test/testCommon.ts b/test/testCommon.ts index a49866af..0a79f470 100644 --- a/test/testCommon.ts +++ b/test/testCommon.ts @@ -190,9 +190,9 @@ export function setFilesExcludePattern () { return filesConfig.update('exclude', files.exclude).then(() => { log.info('[updateFilesExcludePatterns] filesConfig.update success!') return true - }, (err) => { - log.error('[updateFilesExcludePatterns] filesConfig.update failed! err=' + err) - throw err + }, (e: unknown) => { + log.error('[updateFilesExcludePatterns] filesConfig.update failed! err=' + e) + throw e }) } @@ -223,7 +223,7 @@ export function installExtension (extname = 'riversidesoftware.openedge-abl-lsp' throw new Error('get after install failed (undefined)') } return true - }, (e) => { + }, (e: unknown) => { log.error('install failed e=' + e) return false }) @@ -324,7 +324,7 @@ async function waitForExtensionActive (extensionId = 'kherring.ablunit-test-runn .then(() => { log.info('activated? ' + extensionId) return extensions.getExtension(extensionId) - }, (err) => { throw new Error('failed to activate kherring.ablunit-test-runner: ' + err) }) + }, (e: unknown) => { throw new Error('failed to activate kherring.ablunit-test-runner: ' + e) }) log.info('post-activate (ext.isActive=' + ext?.isActive + ')') if (!ext) { throw new Error(extensionId + ' is not installed') } @@ -370,7 +370,7 @@ export async function awaitRCode (workspaceFolder: WorkspaceFolder, rcodeCountMi await commands.executeCommand('abl.project.rebuild').then(() => { log.info('abl.project.rebuild command complete!') return true - }, (e) => { + }, (e: unknown) => { log.error('[awaitRCode] abl.project.rebuild failed! err=' + e) return false }) @@ -577,7 +577,7 @@ export async function runAllTests (doRefresh = true, waitForResults = true, with .then((r) => { log.info(tag + 'command ' + testCommand +' complete! (r=' + r + ')') return sleep(250) - }, (e) => { throw e }) + }, (e: unknown) => { throw e }) .then(() => { log.info(tag + 'testing.runAll completed - start getResults()') if (!waitForResults) { return [] } @@ -590,9 +590,9 @@ export async function runAllTests (doRefresh = true, waitForResults = true, with return doesFileExist(fUri) } return false - }, (err) => { + }, (e: unknown) => { runAllTestsDuration?.stop() - throw new Error('testing.runAll failed: ' + err) + throw new Error('testing.runAll failed: ' + e) }) runAllTestsDuration.stop() log.info(tag + 'runAllTests complete (r=' + r + ')') @@ -613,13 +613,13 @@ export function runTestsInFile (filename: string, len = 1, coverage = false) { return commands.executeCommand('testing.coverageCurrentFile') } return commands.executeCommand('testing.runCurrentFile') - }, (e) => { + }, (e: unknown) => { throw e }) .then((r: unknown) => { runTestsDuration?.stop() return getResults(len) - }, (e) => { + }, (e: unknown) => { runTestsDuration?.stop() throw e }) @@ -645,7 +645,7 @@ export function runTestAtLine (filename: string, line: number, len = 1) { .then(() => { log.info('testing.runAtCursor complete') return - }, (e) => { throw e }) + }, (e: unknown) => { throw e }) } async function waitForRefreshComplete () { @@ -658,7 +658,7 @@ async function waitForRefreshComplete () { .then((r: unknown) => { log.info('isRefreshTestsComplete=' + r) return true - }, (e) => { + }, (e: unknown) => { log.info('isRefreshTestComplete error=' + e) return false }) @@ -678,9 +678,9 @@ export function refreshTests () { .then((r) => { log.info('testing.refreshTests completed! (r=' + r + ')') return true - }, (err) => { - log.info('testing.refreshTests caught an exception. err=' + err) - throw err + }, (e: unknown) => { + log.info('testing.refreshTests caught an exception. err=' + e) + throw e }) } @@ -704,7 +704,7 @@ export async function waitForTestRunStatus (waitForStatus: RunStatus) { return runData[0].status } return RunStatus.None - }, (e) => { + }, (e: unknown) => { log.info('could not get current run data: ' + e) return RunStatus.None }) @@ -794,7 +794,7 @@ export function updateConfig (key: string, value: unknown, configurationTarget?: } log.info('updating configuration section1=' + section2 + ', section2=' + section2 + ', key=' + key + ' value=' + JSON.stringify(value)) return workspaceConfig.update(section2, value, configurationTarget) - .then(() => true, (e) => { throw e }) + .then(() => true, (e: unknown) => { throw e }) } export async function updateTestProfile (key: string, value: string | string[] | boolean | number | object | undefined, workspaceUri?: Uri) { @@ -878,9 +878,9 @@ export function refreshData (resultsLen = 0) { return true } return false - }, (err) => { - log.error('failed to refresh test results: ' + err) - throw new Error('failed to refresh test results: ' + err) + }, (e: unknown) => { + log.error('failed to refresh test results: ' + e) + throw new Error('failed to refresh test results: ' + e) }) } @@ -907,7 +907,7 @@ export function getTestItem (uri: Uri) { const item = i as TestItem log.info('202 item.id=' + item.id) return item - }, (e) => { throw e }) + }, (e: unknown) => { throw e }) } function getType (item: TestItem | undefined) { @@ -988,8 +988,8 @@ export async function getCurrentRunData (len = 1, resLen = 0, tag?: string) { const retResults = await refreshData(resLen).then((r) => { log.debug('refresh success (r=' + r + '; currentRunData.length=' + currentRunData?.length + ')') return true - }, (err) => { - log.error('refresh failed: ' + err) + }, (e: unknown) => { + log.error('refresh failed: ' + e) return false }) diff --git a/test_projects/DebugLines/openedge-project.json b/test_projects/DebugLines/openedge-project.json index bd5351dc..a5b88d5c 100644 --- a/test_projects/DebugLines/openedge-project.json +++ b/test_projects/DebugLines/openedge-project.json @@ -1,6 +1,5 @@ { "name": "DebugLines", - "oeversion": "12.2", "charset": "UTF-8", "dbConnections": [], "graphicalMode": false, diff --git a/test_projects/proj9/openedge-project.json b/test_projects/proj9/openedge-project.json index 8f2189e0..a7b5c954 100644 --- a/test_projects/proj9/openedge-project.json +++ b/test_projects/proj9/openedge-project.json @@ -1,7 +1,7 @@ { "name": "proj9", "buildPath": [ - { "type": "source", "path": "src", "excludes": "emptyClass.cls"}, + { "type": "source", "path": "src", "excludes": "emptyClass.cls,dirA/dir1/testInDir2.p"}, { "type": "source", "path": "test" } ], "numThreads": 1, diff --git a/test_projects/proj9/src/dirA/dir1/testInDir2.p b/test_projects/proj9/src/dirA/dir1/testInDir2.p deleted file mode 100644 index e650f9f0..00000000 --- a/test_projects/proj9/src/dirA/dir1/testInDir2.p +++ /dev/null @@ -1,23 +0,0 @@ -using OpenEdge.Core.Assert. -block-level on error undo, throw. - -@Test. -procedure test_proc : - Assert:Equals(1,1). -end procedure. - -@Test. -procedure dbAliasTest1 : - message "customerTest". - for first dbalias.customer no-lock where dbalias.customer.name begins "b": - message dbalias.customer.name. - end. -end procedure. - -@Test. -procedure dbAliasTest2 : - message "customerTest". - for last third.customer no-lock where third.customer.name begins "b": - message third.customer.name. - end. -end procedure.