diff --git a/CHANGELOG.md b/CHANGELOG.md index 9401a2a8..a32b93a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,3 +15,20 @@ and will be checked for by the extension in the following order - The path set in the extension option **Vectorcast Installation Location** - The path set via the VECTORCAST_DIR environment variable - The system PATH + +## [1.0.3] - 2023-08-07 + +### Added support for "compound only" tests +- Added support for TEST.COMPOUND_ONLY in the script editor +- Included compound only tests in the test tree to allow editing +- Appended "[compound only]" to test names in the test explorer tree +- Added logic to skip execution of compound only tests + +### Fixed a race condition on Load Test Script command +In some cases, the automatic save of the test script was not complete +by the time clicast was called to load the script. + +### Added support for test script option: STRUCT_BASE_CTOR_ADDS_POINTER +This option is new for VectorCAST 23 sp2 + +### Fixed spelling errors / typos in source code comments \ No newline at end of file diff --git a/README.md b/README.md index 1d8783c2..a386556a 100644 --- a/README.md +++ b/README.md @@ -176,7 +176,7 @@ This extension contributes the following settings: before building a new environment - Debugging is only supported for GNU compilers - LSE features for Class Instances have not yet been implemented -- LSE featrures for TEST.FLOW have not been implemented +- LSE features for TEST.FLOW have not been implemented - Deleting a test does not remove the TC annotations in the File Explorer pane ## Contributing diff --git a/package.json b/package.json index ed76216d..dcb18164 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "vectorcasttestexplorer", "displayName": "VectorCAST Test Explorer", "description": "VectorCAST Test Explorer for VS Code", - "version": "1.0.2", + "version": "1.0.3", "license": "See License in file: LICENSE", "repository": { "type": "git", diff --git a/python/tstUtilities.py b/python/tstUtilities.py index fe54951d..2df9c7b2 100644 --- a/python/tstUtilities.py +++ b/python/tstUtilities.py @@ -224,7 +224,7 @@ def processType(type, commandPieces, currentIndex, triggerCharacter): ) elif typeClassification == "array": - # VS Code gives us the closing ] for freee ... + # VS Code gives us the closing ] for free ... # so we only need to recurse when we are past this if len(commandPieces) > currentIndex: # make sure that the string has an index expression ... @@ -295,7 +295,7 @@ def getTestList (api, unitName, functionName): # choiceKindType should match the VS Code CompletionItemKind type -# Suprisingly there is no "parameter" kind, so I just use Field for parameters +# Surprisingly there is no "parameter" kind, so I just use Field for parameters class choiceKindType(str, Enum): Constant='Constant' Enum='Enum' @@ -442,7 +442,7 @@ def processLine(enviroName, line): It will build the choice list for the "next" field based on the line the user has entered so far. - To make this simpler, I did not hande all the edge cases, + To make this simpler, I did not handle all the edge cases, for now I'm using the exception handler. Input examples: @@ -467,7 +467,7 @@ def processLine(enviroName, line): # Intelligently split the line into its fields pieces = splitExistingLine(line) - # if the line ended in a delimeter than the last item in the + # if the line ended in a delimiter than the last item in the # list will be a zero length string, if not it will be a partial # field so we pop it and add a null string if len(pieces[-1]) == 0: @@ -475,10 +475,10 @@ def processLine(enviroName, line): else: pieces.pop() pieces.append("") - # find all delimeters, regex cuz we might have :: in function names. - delimeterList = re.findall(r"(? { connection.sendDiagnostics({ uri: change.document.uri, diagnostics }); }); -// This handler gets called whenever "completion" is triggerd by +// This handler gets called whenever "completion" is triggered by // the characters in the "triggerCharacters" array that onInitialize sets connection.onCompletion( diff --git a/server/serverUtilities.ts b/server/serverUtilities.ts index 7f3b971a..470c615a 100644 --- a/server/serverUtilities.ts +++ b/server/serverUtilities.ts @@ -27,7 +27,7 @@ export function getPieceAtColumn(pieces: string[], columnIndex: number) { let index: number; let endOfPieceIndex: number = 0; for (index = 0; index < pieces.length; index++) { - // +1 for the delimeter + // +1 for the delimiter endOfPieceIndex += pieces[index].length + 1; if (endOfPieceIndex > columnIndex) { return { @@ -45,7 +45,7 @@ export function completionList( choiceKind: CompletionItemKind ): CompletionItem[] { // the format of what comes in here looks like a list of strings - // formated as textValue or textValue@extraInfo + // formatted as textValue or textValue@extraInfo let i; let returnList: CompletionItem[] = []; @@ -205,6 +205,7 @@ export const testCommandList = [ "END_EXPECTED_USER_CODE", "IMPORT_FAILURES", "END_IMPORT_FAILURES", + "COMPOUND_ONLY", ]; export const scriptFeatureList = [ @@ -219,6 +220,7 @@ export const scriptFeatureList = [ "MULTIPLE_UUT_SUPPORT", "OVERLOADED_CONST_SUPPORT", "STANDARD_SPACING_R2", + "STRUCT_BASE_CTOR_ADDS_POINTER", "STRUCT_DTOR_ADDS_POINTER", "STRUCT_FIELD_CTOR_ADDS_POINTER", "STATIC_HEADER_FUNCS_IN_UUTS", diff --git a/server/tstHover.ts b/server/tstHover.ts index 3279f523..ba9c4603 100644 --- a/server/tstHover.ts +++ b/server/tstHover.ts @@ -4,8 +4,6 @@ import { getLineFragment, getLineText, getPieceAtColumn, - completionList, - convertKind, } from "./serverUtilities"; import { TextDocuments, CompletionParams } from "vscode-languageserver"; @@ -30,7 +28,7 @@ export function getHoverString( const fullLine = getLineText(document, completionData.position.line); // generate a list of pieces ... - // this regex creates a set of dilimeters that are either . or : but NOT :: + // this regex creates a set of delimiters that are either . or : but NOT :: const pieces = fullLine.split(/(?>", "<>"]; export function validateTextDocument(textDocument: TextDocument) { // this function does the error checking for the test script - // and generates diagostics for any issues + // and generates diagnostics for any issues let diagnosticList: Diagnostic[] = []; @@ -188,7 +188,7 @@ export function validateTextDocument(textDocument: TextDocument) { ) ); } - } else if (command == "SCRIPT_FEATURE") { + } else if (command == "SCRIPT_FEATURE" && pieces.length>2) { const featureName = pieces[2].trim(); if (scriptFeatureList.indexOf(featureName) < 0) { diagnosticList.push( @@ -232,8 +232,6 @@ export function validateTextDocument(textDocument: TextDocument) { diagnosticList.push(diagnostic(lineIndex, 0, 1000, message)); } - // TBD The lsp example implemented some .relatedInfomration - // for the diagnostic object here ??? } // end for loop return diagnosticList; diff --git a/src-common/commonUtilities.ts b/src-common/commonUtilities.ts index 6052bde3..2cfe25f7 100644 --- a/src-common/commonUtilities.ts +++ b/src-common/commonUtilities.ts @@ -22,15 +22,15 @@ export function getEnviroNameFromScript( return enviroName; } -// Initially I thought I needed to get multiple option, so I implmented this way to make that easy -// but it turns out that I did not really need the SOURCE_EXTENSION ... but I am leaving this as an exmaple +// Initially I thought I needed to get multiple option, so I implemented this way to make that easy +// but it turns out that I did not really need the SOURCE_EXTENSION ... but I am leaving this as an example export interface cfgOptionType { C_DEBUG_CMD: string; SOURCE_EXTENSION: string; } -// we keeep a cache so we don't have to do the parse if +// we keep a cache so we don't have to do the parse if // we've seen this path before var cfgOptionCache: Map = new Map(); diff --git a/src/extension.ts b/src/extension.ts index cffe4f4a..4f7103e7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -43,7 +43,6 @@ import { addSettingsFileFilter, checkIfInstallationIsOK, executeClicastCommand, - initializeChecksumCommand, initializeInstallerFiles, vcastCommandtoUse, } from "./utilities"; diff --git a/src/fileDecorator.ts b/src/fileDecorator.ts index 4f70a70a..76e9b45c 100644 --- a/src/fileDecorator.ts +++ b/src/fileDecorator.ts @@ -62,7 +62,7 @@ export class TreeFileDecorationProvider // this function will replace the existing decorations await this.removeAllCoverageDecorations(); - // convienece function to update a list of files + // convenience function to update a list of files for (let filePath of fileList) { this.addCoverageDecorationToFile(filePath); } @@ -81,7 +81,7 @@ export class TreeFileDecorationProvider async removeAllCoverageDecorations(): Promise { // this will spin through the list of decorated files and remove them - // create a copy of the list so we can destoy the real list was we process each item + // create a copy of the list so we can destroy the real list was we process each item const listCopy = [...this.filesWithCoverage]; for (let index = 0; index < listCopy.length; index++) { // remove the filePath from the real list diff --git a/src/helper.ts b/src/helper.ts index f7e6b3b1..88589c50 100644 --- a/src/helper.ts +++ b/src/helper.ts @@ -1,6 +1,6 @@ import * as vscode from "vscode"; -// some functions that are used across functional areas of the extentions +// some functions that are used across functional areas of the extensions import { updateDisplayedCoverage } from "./coverage"; import { @@ -22,7 +22,7 @@ export function showSettings() { export function updateDataForEnvironment(enviroPath: string) { // this function does all of the "common" work when an environment is updated // sources of environment update are things like: - // - opening the environent in the vcast gui + // - opening the environment in the vcast gui // - building a new environment // - ... diff --git a/src/testData.ts b/src/testData.ts index e46857a3..b0fc0aa9 100644 --- a/src/testData.ts +++ b/src/testData.ts @@ -1,3 +1,5 @@ +export const compoundOnlyString = " [compound only]"; + export interface testNodeType { enviroPath: string; // the full path including the enviro directory enviroName: string; // the directory name @@ -6,7 +8,7 @@ export interface testNodeType { testName: string; } // this is a lookup table for the nodes in the test tree -// the key is the nodeID, the data is an testNodeDataType +// the key is the nodeID, the data is an testNodeType var testNodeCache = new Map(); export function createTestNodeinCache( @@ -66,5 +68,6 @@ export function getFunctionNameFromID(nodeID: string): string { } export function getTestNameFromID(nodeID: string): string { - return testNodeCache.get(nodeID).testName; + const testName = testNodeCache.get(nodeID).testName; + return testName.replace (compoundOnlyString,""); } diff --git a/src/testPane.ts b/src/testPane.ts index d3650d50..1b02b688 100644 --- a/src/testPane.ts +++ b/src/testPane.ts @@ -20,6 +20,7 @@ import { viewResultsReport } from "./reporting"; import { addTestNodeToCache, clearTestNodeCache, + compoundOnlyString, createTestNodeinCache, duplicateTestNode, getEnviroPathFromID, @@ -102,9 +103,12 @@ function addTestNodes( notes: testList[testIndex].notes, resultFilePath: "", URI: fileURI, + compoundOnly: testList[testIndex].compoundOnly, }; - const testName = testList[testIndex].testName; + let testName = testList[testIndex].testName; + if (testData.compoundOnly) + testName += compoundOnlyString; const testNodeID = parentNodeID + "." + testName; // add a cache node for the test @@ -119,6 +123,7 @@ function addTestNodes( fileURI ); testNode.nodeKind = nodeKind.test; + testNode.isCompoundOnly = testData.compoundOnly; if (fileURI) testNode.range = getTestLocation(fileURI, testName); parentNode.add(testNode); } @@ -157,7 +162,7 @@ export async function openTestScript(nodeID: string) { if (commandStatus.errorCode == 0) { // Improvement needed: // It would be nice if vcast generated the scripts with TEST.REPLACE, but for now - // convert TEST.NEW to TEST.REPLACE so doing an "immedidate load" works without error + // convert TEST.NEW to TEST.REPLACE so doing an "immediate load" works without error convertTestScriptContents(scriptPath); // open the script file for editing @@ -184,7 +189,8 @@ export async function loadTestScript() { const activeEditor = vscode.window.activeTextEditor; if (activeEditor) { if (activeEditor.document.isDirty) { - activeEditor.document.save(); + // need to wait, otherwise we have a race condition with clicast + await activeEditor.document.save(); } let scriptPath = url.fileURLToPath(activeEditor.document.uri.toString()); const enviroName = getEnviroNameFromScript(scriptPath); @@ -291,7 +297,7 @@ function processVCtestData( } const testList = unitData.tests; - // we insert not-used to make the format of the IDs consisten + // we insert not-used to make the format of the IDs consistent // this gets stripped off/processed in the functions // -- getClicastArgsFromTestNode() -- ts // -- getStandardArgsFromTestObject() -- python @@ -330,7 +336,7 @@ function getEnvironmentList(baseDirectory: string): string[] { // so turn this into a list of the enclosing directories only let returnList: string[] = []; for (const file of fileList) { - // note that glob always usees / as path separator ... + // note that glob always uses / as path separator ... if (!file.includes(".BAK")) { returnList.push(path.dirname(file)); } @@ -340,7 +346,7 @@ function getEnvironmentList(baseDirectory: string): string[] { } // This is intended to be used in the package.json to control the display of context menu items -// Search for 'vectorcastTestExplorer.vcastEnviroList' in package.json to seee where we reference +// Search for 'vectorcastTestExplorer.vcastEnviroList' in package.json to see where we reference // this list in a "when" clause export var vcastEnviroList: string[] = []; @@ -602,7 +608,7 @@ async function debugNode( // Here are the steps needed to debug. // - Check if we have a single test selected, if not do normal run // - Check if we are gcc/gdb, if now issue a warning and do normal run - // - Disable coverage so that the UUT source code is more readble + // - Disable coverage so that the UUT source code is more readable // - Run the test without debug to setup all the test input files // - Open the file: _vcast.cpp -> this is the source that will run // - Start debugger using the VectorCAST launch configuration @@ -838,6 +844,7 @@ async function runTests( const run = controller.createTestRun(request); for (const test of testList) { if (cancellation.isCancellationRequested) run.skipped(test); + else if (test.isCompoundOnly) run.skipped(test); else await runNode(test, run); // used to allow the message window to display properly await new Promise((r) => setTimeout(r, 0)); @@ -863,11 +870,17 @@ async function processRunRequest( cancellation: vscode.CancellationToken, isDebug: boolean = false ) { - // debug is only valid for a single test node + + // Debug is only valid for a single test node + // requests.include will be null if the request is for all tests + // or it will have a list if the request is for one or more tests + // isSingleTestNode checks if it is exactly one and it is a test + // not a unit, function, ... if (isDebug && request.include && isSingleTestNode(request)) { const node = request.include[0]; debugNode(controller, request, node); - } else { + } + else { // tell user that we are doing a normal run ... if (isDebug) { vscode.window.showInformationMessage( @@ -964,9 +977,11 @@ export interface vcastTestItem extends vscode.TestItem { // Thought I could use this in a package.json when clause // but have not figured this out yet. - // kind of node - not currently used nodeKind?: nodeKind; + // used to inhibit run for compound only tests + isCompoundOnly?:boolean; + // this is used for unit nodes to keep track of the // full path to the source file sourcePath?: string; diff --git a/src/utilities.ts b/src/utilities.ts index 77b20012..3e941661 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -6,7 +6,6 @@ import { showSettings } from "./helper"; const execSync = require("child_process").execSync; const spawn = require("child_process").spawn; -const hasbin = require("hasbin"); const fs = require("fs"); const path = require("path"); const which = require ("which") @@ -24,7 +23,7 @@ export let vcastCommandtoUse: string | undefined = undefined; // The testInterface is delivered int the .vsix // in the sub-directory "python" -// The VectorCAST extensioons for settings and launch are delivered in the .vsix +// The VectorCAST extensions for settings and launch are delivered in the .vsix // in the sub-directory "support" export let globalTestInterfacePath: string | undefined = undefined; @@ -58,7 +57,7 @@ export function initializeInstallerFiles(context: vscode.ExtensionContext) { const pathToSupportFiles = context.asAbsolutePath("./supportFiles"); if (fs.existsSync(pathToSupportFiles)) { - vectorMessage("Found extension suppoort files here: " + pathToSupportFiles); + vectorMessage("Found extension support files here: " + pathToSupportFiles); globalPathToSupportFiles = `${pathToSupportFiles}`; } } @@ -68,7 +67,7 @@ export function testInterfaceCommand( enviroPath: string, testID: string = "" ): any | undefined { - // enviroPath is the absolute path to the environnment directory + // enviroPath is the absolute path to the environnement directory // testID is contains the string that uniquely identifies the node, something like: // 'Environments-GCC/TUTORIAL-C++-4|manager.Manager::PlaceOrder.Manager::PlaceOrder.001' @@ -148,7 +147,7 @@ export function getChecksumCommand() { } export function loadLaunchFile(jsonPath: string): any { - // this funciton takes the path to a launch.json + // this function takes the path to a launch.json // and returns the contents, or an empty list of configurations // if we cannot read the file let existingJSON: any; @@ -240,7 +239,7 @@ export function executeVPythonScript( commandToRun: string, whereToRun: string ): any { - // we use this common functon to run the vpython and process the output because + // we use this common function to run the vpython and process the output because // vpython prints this annoying message if VECTORCAST_DIR does not match the executable // Since this happens before our script even starts so we cannot suppress it. // We could send the json data to a temp file, but the create/open file operations diff --git a/src/vcastTestInterface.ts b/src/vcastTestInterface.ts index 210fcbb3..c3e84063 100644 --- a/src/vcastTestInterface.ts +++ b/src/vcastTestInterface.ts @@ -9,7 +9,11 @@ import { vcastMessage, errorLevel, } from "./messagePane"; -import { getEnviroPathFromID, getTestNode, testNodeType } from "./testData"; +import { + compoundOnlyString, + getEnviroPathFromID, + getTestNode, + testNodeType } from "./testData"; import { clicastCommandToUse, commandStatusType, @@ -117,6 +121,7 @@ export interface testDataType { resultFilePath: string; notes: string; URI: vscode.Uri | undefined; + compoundOnly: boolean; } // This allows us to get diret access to the test nodes via the ID @@ -575,7 +580,7 @@ function commonNewEnvironmentStuff( const filename = path.basename(firstFile); let enviroName = filename.split(".")[0].toUpperCase(); - // if multiple files are in the list make the environame the hyphenated name of the first 2 + // if multiple files are in the list make the enviroName the hyphenated name of the first 2 if (fileList.length > 1) { enviroName += `-${path .basename(fileList[1]) @@ -619,7 +624,7 @@ function commonNewEnvironmentStuff( } else vectorMessage("No C/C++ source files found in selection ..."); } -// Improvement needed: get the language extensions automatcally, don't hard-code +// Improvement needed: get the language extensions automatically, don't hard-code const extensionsOfInterest = ["c", "cpp", "cc", "cxx"]; export function newEnvironment(URIlist: Uri[]) { @@ -755,7 +760,7 @@ export function getClicastArgsFromTestNode(testNode: testNodeType) { // we need the quotes on the names to handle <> and <> if (testNode.functionName.length > 0) returnString += ` -s"${testNode.functionName}"`; - if (testNode.testName.length > 0) returnString += ` -t"${testNode.testName}"`; + if (testNode.testName.length > 0) returnString += ` -t"${testNode.testName.replace (compoundOnlyString,"")}"`; return returnString; } diff --git a/syntax/vcast.tst.grammar.json b/syntax/vcast.tst.grammar.json index 61a2759b..7675ae49 100644 --- a/syntax/vcast.tst.grammar.json +++ b/syntax/vcast.tst.grammar.json @@ -11,7 +11,7 @@ "name": "comment.line" }, { - "match": "^TEST\\.(?:NEW|REPLACE|ADD|END)(\\s|$)", + "match": "^TEST\\.(?:NEW|REPLACE|ADD|END|COMPOUND_ONLY)(\\s|$)", "name": "keyword" }, { diff --git a/tests/internal/e2e/test/specs/vcast.test.ts b/tests/internal/e2e/test/specs/vcast.test.ts index a3ae58dc..cdc00688 100644 --- a/tests/internal/e2e/test/specs/vcast.test.ts +++ b/tests/internal/e2e/test/specs/vcast.test.ts @@ -402,7 +402,7 @@ describe("vTypeCheck VS Code Extension", () => { // this produces invalid locator error somehow // const contMenu = await tab.openContextMenu() - // const menuItem = await contMenu.getItem("Load Test Script intto Environment") + // const menuItem = await contMenu.getItem("Load Test Script into Environment") // await menuItem.select() // Loading test script directly for now diff --git a/tests/unit/tstCompletion.test.ts b/tests/unit/tstCompletion.test.ts index 782d33d7..c41b5303 100644 --- a/tests/unit/tstCompletion.test.ts +++ b/tests/unit/tstCompletion.test.ts @@ -306,35 +306,41 @@ describe("Text Completion", () => { data: 10, }, { - label: "STRUCT_DTOR_ADDS_POINTER", + label: "STRUCT_BASE_CTOR_ADDS_POINTER", kind: 14, detail: "", data: 11, }, { - label: "STRUCT_FIELD_CTOR_ADDS_POINTER", + label: "STRUCT_DTOR_ADDS_POINTER", kind: 14, detail: "", data: 12, }, { - label: "STATIC_HEADER_FUNCS_IN_UUTS", + label: "STRUCT_FIELD_CTOR_ADDS_POINTER", kind: 14, detail: "", data: 13, }, { - label: "UNDERSCORE_NULLPTR", + label: "STATIC_HEADER_FUNCS_IN_UUTS", kind: 14, detail: "", data: 14, }, { - label: "VCAST_MAIN_NOT_RENAMED", + label: "UNDERSCORE_NULLPTR", kind: 14, detail: "", data: 15, }, + { + label: "VCAST_MAIN_NOT_RENAMED", + kind: 14, + detail: "", + data: 16, + }, ]); }, timeout @@ -519,6 +525,12 @@ describe("Text Completion", () => { detail: "", data: 21, }, + { + label: "COMPOUND_ONLY", + kind: 14, + detail: "", + data: 22, + } ]); }, timeout