diff --git a/package.json b/package.json index 8cb08977..683dc4f0 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,10 @@ "command": "vectorcastTestExplorer.createNewProject", "title": "VectorCAST: Create New Project" }, + { + "command": "vectorcastTestExplorer.createNewCFG", + "title": "VectorCAST: Create New CFG" + }, { "command": "vectorcastTestExplorer.configure", "category": "VectorCAST Test Explorer", @@ -169,6 +173,11 @@ "category": "VectorCAST Test Explorer", "title": "Create VectorCAST Environment" }, + { + "command": "vectorcastTestExplorer.defaultVCShell", + "category": "VectorCAST Test Explorer", + "title": "Set as default Database" + }, { "command": "vectorcastTestExplorer.newEnviroInProjectVCAST", "category": "VectorCAST Test Explorer", @@ -381,6 +390,12 @@ "default": "", "description": "The file path to an existing VectorCAST configuration that should be used when creating new environments. If a value is not specified, the configuration editor will be launched" }, + "vectorcastTestExplorer.databaseLocation": { + "type": "string", + "order": 4, + "default": "", + "description": "The file path to an existing VectorCAST database file that should be used when creating new environments." + }, "vectorcastTestExplorer.showReportOnExecute": { "type": "boolean", "order": 5, @@ -624,7 +639,11 @@ "file/newFile": [ { "command": "vectorcastTestExplorer.createNewProject", - "group": "1_createnew" + "group": "VectorCAST: New Ressources" + }, + { + "command": "vectorcastTestExplorer.createNewCFG", + "group": "VectorCAST: New Ressources" } ], "commandPalette": [ @@ -719,6 +738,10 @@ "command": "vectorcastTestExplorer.newEnviroVCAST", "when": "never" }, + { + "command": "vectorcastTestExplorer.defaultVCShell", + "when": "never" + }, { "command": "vectorcastTestExplorer.newEnviroInProjectVCAST", "when": "never" @@ -870,6 +893,11 @@ "when": "resourceLangId == cpp || resourceLangId == c", "group": "2_workspace" }, + { + "command": "vectorcastTestExplorer.defaultVCShell", + "when": "vectorcastTestExplorer.configured && resourceExtname==.db", + "group": "2_workspace" + }, { "command": "vectorcastTestExplorer.newEnviroInProjectVCAST", "when": "(resourceLangId == cpp || resourceLangId == c) && vectorcastTestExplorer.globalProjectIsOpenedChecker", diff --git a/src/extension.ts b/src/extension.ts index 1caa308f..51ec1d47 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -79,6 +79,7 @@ import { forceLowerCaseDriveLetter, decodeVar, getFullEnvReport, + normalizePath, } from "./utilities"; import { @@ -149,6 +150,10 @@ import { newTestScript, openCodedTest, ProjectEnvParameters, + createNewCFGFile, + ConfigurationOptions, + updateVCShellDatabase, + updateCFGWithVCShellDatabase, } from "./vcastTestInterface"; import { @@ -1546,6 +1551,51 @@ async function installPreActivationEventHandlers( ); context.subscriptions.push(newEnviroVCASTCommand); + let defaultVCShellCommand = vscode.commands.registerCommand( + "vectorcastTestExplorer.defaultVCShell", + async (fileURI: Uri) => { + await checkPrerequisites(context); + + if (!alreadyConfigured) { + return; + } + + if (fileURI) { + const filePath = fileURI.fsPath; + const settings = vscode.workspace.getConfiguration( + "vectorcastTestExplorer" + ); + + const defaultConfigurationPath = settings.get( + "configurationLocation", + undefined + ); + + // First update vcshell db setting + await updateVCShellDatabase(filePath); + + // In case we have a default cfg, ask the user if he wants to update the cfg with the current default vcshell db + if (defaultConfigurationPath) { + const choice = await vscode.window.showWarningMessage( + `You have set a default CFG at ${defaultConfigurationPath}. Do you want to include your database in that configuration?`, + { modal: false }, + "Yes", + "No" + ); + + if (choice === "Yes") { + const normalizedCFGPath = normalizePath( + path.dirname(defaultConfigurationPath) + ); + await updateCFGWithVCShellDatabase(filePath, normalizedCFGPath); + } + } + } + } + ); + + context.subscriptions.push(defaultVCShellCommand); + const importEnviroToProject = vscode.commands.registerCommand( "vectorcastTestExplorer.importEnviroToProject", async (_args: vscode.Uri, argList: vscode.Uri[]) => { @@ -1982,32 +2032,74 @@ async function installPreActivationEventHandlers( projectName?: string; compilerName?: string; targetDir?: string; + useDefaultCFG?: boolean; + enableCodedTests?: boolean; + defaultCFG?: boolean; + useDefaultDB?: boolean; }) { - const { projectName, compilerName, targetDir } = message; - // Make sure that Inputs have to be filled and the compiler tag is found + const { + projectName, + compilerName, + targetDir, + useDefaultCFG, + enableCodedTests, + defaultCFG, + useDefaultDB, + } = message; + if (!projectName) { vscode.window.showErrorMessage("Project Name is required."); return; } - if (!compilerName) { - vscode.window.showErrorMessage("Compiler selection is required."); - return; - } - const compilerTag = compilerTagList[compilerName]; - if (!compilerTag) { - vscode.window.showErrorMessage( - `No compiler tag found for "${compilerName}".` + + let compiler: string | undefined; + let configurationOptions: ConfigurationOptions | undefined; + + if (useDefaultCFG) { + const settings = vscode.workspace.getConfiguration( + "vectorcastTestExplorer" ); - return; + const defaultCFGPath = settings.get("configurationLocation"); + + if (!defaultCFGPath) { + vscode.window.showErrorMessage("No default CFG is defined."); + return; + } + // When using default CFG, the 'compiler' string is the path to the CFG + compiler = defaultCFGPath; + } else { + // Manual Compiler Selection + if (!compilerName) { + vscode.window.showErrorMessage("Compiler selection is required."); + return; + } + + compiler = compilerTagList[compilerName]; + if (!compiler) { + vscode.window.showErrorMessage( + `No compiler tag found for "${compilerName}".` + ); + return; + } + + // Pack the boolean options + configurationOptions = { + enableCodedTests: !!enableCodedTests, + defaultCFG: !!defaultCFG, + useDefaultDB: !!useDefaultDB, + }; } const base = targetDir ?? workspaceRoot; const projectPath = path.join(base, projectName); - vscode.window.showInformationMessage( - `Creating project "${projectName}" at ${projectPath} using ${compilerName}.` + await createNewProject( + projectPath, + compiler, + !!useDefaultCFG, + configurationOptions ); - await createNewProject(projectPath, compilerTag); + panel.dispose(); } } @@ -2015,6 +2107,7 @@ async function installPreActivationEventHandlers( context.subscriptions.push(createNewProjectCmd); + // Helper function for Webview Content async function getNewProjectWebviewContent( context: vscode.ExtensionContext, panel: vscode.WebviewPanel, @@ -2031,21 +2124,35 @@ async function installPreActivationEventHandlers( const scriptUri = panel.webview.asWebviewUri(scriptOnDisk); const compilersJson = JSON.stringify(Object.keys(compilerTagList)); - // pass default targetDir as workspace root const workspaceJson = JSON.stringify(workspaceRoot); + const settings = vscode.workspace.getConfiguration( + "vectorcastTestExplorer" + ); + const defaultCFG = settings.get("configurationLocation") ?? ""; + + // Check default DB setting and if file exists + const dbSettingPath = settings.get("databaseLocation"); + let validDBPath = ""; + if (dbSettingPath && fs.existsSync(dbSettingPath)) { + validDBPath = dbSettingPath; + } + let html = fs.readFileSync(htmlPath, "utf8"); const nonce = getNonce(); + html = html.replace( //, ` - - ` + + ` ); html = html.replace("{{ cssUri }}", cssUri.toString()); html = html.replace( @@ -2180,6 +2287,146 @@ async function installPreActivationEventHandlers( return html; } + + const createNewCFGCmd = vscode.commands.registerCommand( + "vectorcastTestExplorer.createNewCFG", + async () => { + const workspaceFolders = vscode.workspace.workspaceFolders; + if (!workspaceFolders?.length) { + vscode.window.showErrorMessage("Open a folder first."); + return; + } + const workspaceRoot = workspaceFolders[0].uri.fsPath; + + const baseDir = resolveWebviewBase(context); + const panel = vscode.window.createWebviewPanel( + "newCFG", + "Create New CFG File", + vscode.ViewColumn.Active, + { + enableScripts: true, + retainContextWhenHidden: true, + localResourceRoots: [vscode.Uri.file(baseDir)], + } + ); + + panel.webview.html = await getNewCFGWebviewContent( + context, + panel, + compilerTagList + ); + + panel.webview.onDidReceiveMessage( + async (msg) => { + switch (msg.command) { + case "submit": { + const compilerName: string | undefined = msg.compilerName?.trim(); + const enableCodedTests: boolean = !!msg.enableCodedTests; + const defaultCFG: boolean = !!msg.defaultCFG; + // Extract the new toggle value + const useDefaultDB: boolean = !!msg.useDefaultDB; + + const configurationOptions: ConfigurationOptions = { + enableCodedTests: enableCodedTests, + defaultCFG: defaultCFG, + useDefaultDB: useDefaultDB, + }; + + if (!compilerName) { + vscode.window.showErrorMessage( + "Compiler selection is required." + ); + return; + } + + const compilerTag = compilerTagList[compilerName]; + if (!compilerTag) { + vscode.window.showErrorMessage( + `No compiler tag found for "${compilerName}".` + ); + return; + } + + // Pass flags to implementation + await createNewCFGFile( + workspaceRoot, + compilerTag, + configurationOptions + ); + + panel.dispose(); + break; + } + } + }, + undefined, + context.subscriptions + ); + } + ); + + context.subscriptions.push(createNewCFGCmd); + + async function getNewCFGWebviewContent( + context: vscode.ExtensionContext, + panel: vscode.WebviewPanel, + compilerTagList: Record + ): Promise { + // Build paths for webview files + const base = resolveWebviewBase(context); + const cssOnDisk = vscode.Uri.file(path.join(base, "css", "newCFG.css")); + const scriptOnDisk = vscode.Uri.file( + path.join(base, "webviewScripts", "newCFG.js") + ); + const htmlPath = path.join(base, "html", "newCFG.html"); + + // convert to URI + const cssUri = panel.webview.asWebviewUri(cssOnDisk); + const scriptUri = panel.webview.asWebviewUri(scriptOnDisk); + + // JSON list of compilers for autocomplete + const compilerList = JSON.stringify(Object.keys(compilerTagList ?? {})); + + // Check DB Setting + const settings = vscode.workspace.getConfiguration( + "vectorcastTestExplorer" + ); + const dbSettingPath = settings.get("databaseLocation"); + let validDBPath = ""; + if (dbSettingPath && fs.existsSync(dbSettingPath)) { + validDBPath = dbSettingPath; + } + + let html = fs.readFileSync(htmlPath, "utf8"); + const nonce = getNonce(); + + // build CSP meta (need to allow our scripts with our generated nonce) + const csp = ` + + `; + + // Insert CSP immediately after the opening + html = html.replace(//i, `${csp}`); + html = html.replace(/{{\s*cssUri\s*}}/g, cssUri.toString()); + html = html.replace( + /<\/script>/i, + `` + ); + + // Inline script to expose compilerData, enableCodedTests, and defaultDB to the webview client + const injectedScript = ``; + html = html.replace(/\{\{\s*compilerDataScript\s*\}\}/g, injectedScript); + + return html; + } } // this method is called when your extension is deactivated diff --git a/src/manage/manageSrc/manageCommands.ts b/src/manage/manageSrc/manageCommands.ts index ae7d82d9..9e046812 100644 --- a/src/manage/manageSrc/manageCommands.ts +++ b/src/manage/manageSrc/manageCommands.ts @@ -23,7 +23,10 @@ import { getEnviroNodeData } from "../../testData"; import { executeWithRealTimeEchoWithProgress } from "../../vcastCommandRunner"; -import { manageCommandToUse } from "../../vcastInstallation"; +import { + getVectorCastInstallationLocation, + manageCommandToUse, +} from "../../vcastInstallation"; import { checkIfEnvironmentIsBuildMultipleTimes, @@ -44,6 +47,10 @@ import { } from "../../testPane"; import { normalizePath } from "../../utilities"; import { viewResultsReportVC } from "../../reporting"; +import { + ConfigurationOptions, + updateCFGWithVCShellDatabase, +} from "../../vcastTestInterface"; const path = require("path"); @@ -121,12 +128,20 @@ export async function createNewCompilerInProject( /** * Creates a new Project including a new Compiler * @param projectPath Path to the new project file - * @param compiler Compiler Name + * @param compiler Compiler Tag OR compiler path in case we are using the default CFG from the settings + * @param usingDefaultCFG Boolean, if the user selected to use the default cfg in the settings */ -export async function createNewProject(projectPath: string, compiler: string) { +export async function createNewProject( + projectPath: string, + compiler: string, + usingDefaultCFG: boolean = false, + configurationOptions?: ConfigurationOptions +) { const projectName = path.basename(projectPath); const projectLocation = path.dirname(projectPath); - const progressMessage = `Creating new Project ${projectName} ...`; + + // Create the Project Directory Structure + const progressMessage = `Creating new Project ${projectName} ...`; const manageArgs = [`-p${projectName}`, `--create`, "--force"]; await executeWithRealTimeEchoWithProgress( @@ -136,7 +151,91 @@ export async function createNewProject(projectPath: string, compiler: string) { progressMessage ); - await createNewCompilerInProject(projectPath, compiler); + let activeCFGPath: string | undefined; + + // Configure the Compiler / CFG + if (usingDefaultCFG) { + // Scenario A: Use an existing CFG file + // 'compiler' variable here is the PATH to the CFG + activeCFGPath = compiler; + await addCompilerToProject(projectPath, compiler); + } else { + // Scenario B: Create a NEW CFG based on a Compiler Tag + // 'compiler' variable here is the Compiler Tag (e.g., "GNU_Native") + + // Create the CFG file inside the new project directory + const createdCfgPath = await createNewCFGFromCompiler( + compiler, + projectPath + ); + + activeCFGPath = createdCfgPath; + + // Handle Additional Configuration Options (if provided) + if (configurationOptions) { + const vcDir = getVectorCastInstallationLocation(); + if (vcDir) { + const clicastCmd = path.join(vcDir, "clicast"); + + // Apply Coded Tests Option + const codedFlag = configurationOptions.enableCodedTests + ? "TRUE" + : "FALSE"; + const codedOptionArgs = [ + "-lc", + "option", + "VCAST_CODED_TESTS_SUPPORT", + codedFlag, + ]; + + // We run this command INSIDE the new project path so it affects the local CFG + await executeWithRealTimeEchoWithProgress( + clicastCmd, + codedOptionArgs, + projectPath, + "Setting VCAST_CODED_TESTS_SUPPORT in Project CFG" + ); + + // Set as Default CFG in VS Code Settings + if (configurationOptions.defaultCFG) { + const settings = vscode.workspace.getConfiguration( + "vectorcastTestExplorer" + ); + await settings.update( + "configurationLocation", + createdCfgPath, + vscode.ConfigurationTarget.Workspace + ); + } + } else { + vscode.window.showErrorMessage( + "Could not determine VectorCAST location. configuration options could not be applied." + ); + } + } + + // If CFG options are done, add the compiler to the project + // If the path would be undefined, we will get a message from createNewCFGFromCompiler, so no handling here + if (createdCfgPath) { + await addCompilerToProject(projectPath, createdCfgPath); + } + } + + // Apply Default Database if requested and path exists + if (configurationOptions?.useDefaultDB && activeCFGPath) { + const settings = vscode.workspace.getConfiguration( + "vectorcastTestExplorer" + ); + const dbPath = settings.get("databaseLocation"); + + if (dbPath && fs.existsSync(dbPath)) { + await updateCFGWithVCShellDatabase(dbPath, activeCFGPath); + } else { + vscode.window.showWarningMessage( + "Could not set Default Database: The database file defined in settings could not be found." + ); + } + } } export async function cleanProjectEnvironment( diff --git a/src/manage/webviews/css/newCFG.css b/src/manage/webviews/css/newCFG.css new file mode 100644 index 00000000..452d744c --- /dev/null +++ b/src/manage/webviews/css/newCFG.css @@ -0,0 +1,254 @@ +/* Reset and base */ +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + background-color: #1e1e1e; + color: #d4d4d4; + display: flex; + align-items: center; + justify-content: center; + height: 100vh; +} + +/* Modal container */ +.modal { + width: 700px; + background-color: #252526; + padding: 25px; + border-radius: 8px; + box-shadow: 0 0 10px rgba(0,0,0,0.3); + display: flex; + flex-direction: column; +} + +/* Modal title */ +.modal h2 { + text-align: center; + color: #ffffff; + margin-bottom: 15px; + font-size: 22px; +} + +/* Labels and inputs */ +label, .toggle-label { + font-size: 16px; + color: #d4d4d4; +} + +input[type="text"], select { + padding: 10px; + font-size: 14px; + background-color: #3c3c3c; + color: #d4d4d4; + border: 1px solid #555; + border-radius: 4px; + width: 100%; +} + +/* Folder-picker row */ +.single-input-container { + display: grid; + grid-template-columns: 1fr auto; + gap: 10px; + align-items: center; + margin-bottom: 15px; +} + +/* “Select” button beside the input */ +.select-button { + background-color: #007acc; + color: white; + border: none; + border-radius: 4px; + padding: 10px 16px; + font-size: 14px; + cursor: pointer; + transition: background-color 0.3s; +} + +.select-button:hover { + background-color: #005f99; +} + +/* Add spacing between label and autocomplete */ +label[for="compilerInput"] { + margin-bottom: 10px; +} + +/* Autocomplete */ +.autocomplete { + position: relative; + width: 100%; +} + +.suggestions { + position: absolute; + top: 100%; + left: 0; + right: 0; + background: #2a2a2a; + border: 1px solid #555; + max-height: 180px; + overflow-y: auto; + list-style: none; + padding: 0; + margin-top: 4px; + display: none; + z-index: 10; + text-align: left; +} + +.suggestions.visible { + display: block; +} + +.suggestions li { + padding: 8px 12px; + cursor: pointer; + font-size: 14px; +} + +.suggestions li:hover, +.suggestions li.active { + background: #007acc; + color: white; +} + +/* =========================== + Options section + =========================== */ +.options-section { + margin-top: 20px; + padding-top: 10px; + border-top: 1px solid #444; + width: 80%; + margin-left: auto; + margin-right: auto; +} + +.options-section h3 { + font-size: 16px; + font-weight: 600; + margin-bottom: 10px; + color: #ffffff; + text-align: center; +} + +.option-row { + display: flex; + align-items: center; + justify-content: space-between; + padding: 6px 0; + width: 100%; +} + +.option-row .toggle-label { + font-size: 16px; + color: #d4d4d4; +} + +/* =========================== + VS Code–style toggle + =========================== */ +.vscode-toggle { + display: inline-block; + cursor: pointer; +} + +.toggle-switch { + display: inline-block; + position: relative; + width: 44px; + height: 24px; +} + +.toggle-switch input { + opacity: 0; + width: 0; + height: 0; + margin: 0; +} + +.toggle-switch .slider { + position: absolute; + inset: 0; + background: #3c3c3c; + border: 1px solid #555; + border-radius: 12px; + transition: background 0.12s ease, border-color 0.12s ease; + box-sizing: border-box; +} + +.toggle-switch .slider::before { + content: ""; + position: absolute; + top: 50%; + left: 1px; + width: 22px; + height: 22px; + border-radius: 50%; + background: #d4d4d4; + box-shadow: 0 1px 0 rgba(0,0,0,0.25); + transform: translateY(-50%); + transition: left 0.12s ease, background 0.12s ease; +} + +.toggle-switch input:checked + .slider { + background: #007acc; + border-color: #007acc; +} + +.toggle-switch input:checked + .slider::before { + left: 21px; + background: #ffffff; +} + +.toggle-switch input:focus + .slider { + box-shadow: 0 0 0 3px rgba(0,122,204,0.14); +} + +.vscode-toggle:hover .slider { + filter: brightness(1.06); +} + +/* =========================== + Buttons + =========================== */ +.button-container { + display: flex; + justify-content: space-between; /* cancel left, create right */ + margin-top: 25px +} + +.primary-button, +.cancel-button { + padding: 10px 20px; + font-size: 16px; + border: none; + border-radius: 4px; + cursor: pointer; + transition: background-color 0.3s; +} + +.primary-button { + background-color: #007acc; + color: white; +} + +.primary-button:hover { + background-color: #005f99; +} + +.cancel-button { + background-color: #cc4444; + color: white; +} + +.cancel-button:hover { + background-color: #992222; +} diff --git a/src/manage/webviews/css/newProject.css b/src/manage/webviews/css/newProject.css index 5be0367a..e386e4a8 100644 --- a/src/manage/webviews/css/newProject.css +++ b/src/manage/webviews/css/newProject.css @@ -22,36 +22,46 @@ body { padding: 25px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.3); + display: flex; + flex-direction: column; + max-height: 95vh; + overflow-y: auto; } -/* Center only the title, not all modal text */ +/* Modal Main Title */ .modal h2 { text-align: center; -} - -h2 { color: #ffffff; - margin-bottom: 15px; + margin-bottom: 20px; font-size: 22px; + font-weight: 600; } -/* Labels and inputs */ -label { - font-size: 16px; +/* Generic Labels */ +label, .toggle-label { + font-size: 14px; + color: #cccccc; display: block; - text-align: left; - margin-top: 12px; margin-bottom: 6px; + font-weight: 400; } +/* Inputs */ input[type="text"], select { - padding: 10px; + padding: 8px 10px; font-size: 14px; background-color: #3c3c3c; color: #d4d4d4; - border: 1px solid #555; + border: 1px solid #3c3c3c; border-radius: 4px; width: 100%; + margin-bottom: 15px; + transition: border-color 0.2s; +} + +input[type="text"]:focus, select:focus { + border-color: #007acc; + outline: none; } /* Folder-picker row */ @@ -59,98 +69,246 @@ input[type="text"], select { display: grid; grid-template-columns: 1fr auto; gap: 10px; - align-items: center; + align-items: start; margin-bottom: 15px; } +.single-input-container input[type="text"] { + margin-bottom: 0; +} -/* “Select” button beside the input */ +/* Select Button */ .select-button { background-color: #007acc; color: white; border: none; border-radius: 4px; - padding: 10px 16px; + padding: 0 16px; font-size: 14px; cursor: pointer; + height: 35px; /* Match input height */ transition: background-color 0.3s; + display: flex; + align-items: center; } - -.select-button:hover { - background-color: #005f99; -} +.select-button:hover { background-color: #005f99; } /* Autocomplete */ .autocomplete { position: relative; width: 100%; } - .suggestions { position: absolute; top: 100%; left: 0; right: 0; - background: #2a2a2a; - border: 1px solid #555; + background: #252526; + border: 1px solid #454545; max-height: 180px; overflow-y: auto; list-style: none; padding: 0; - margin-top: 4px; + margin-top: 2px; display: none; - z-index: 10; - text-align: left; /* ensure left alignment */ -} - -.suggestions.visible { - display: block; + z-index: 100; + box-shadow: 0 4px 6px rgba(0,0,0,0.3); } - +.suggestions.visible { display: block; } .suggestions li { padding: 8px 12px; cursor: pointer; font-size: 14px; + border-bottom: 1px solid #333; } - +.suggestions li:last-child { border-bottom: none; } .suggestions li:hover, .suggestions li.active { background: #007acc; color: white; } -/* Button container */ +/* ========================================= + Options Section & Headers + ========================================= */ + +.options-section { + margin-top: 15px; + padding-top: 15px; + border-top: 1px solid #3e3e3e; + width: 98%; + margin-left: auto; + margin-right: auto; +} + +/* MAIN SECTION TITLE (Compiler Selection) */ +.options-section h3 { + font-size: 16px; + font-weight: 700; + color: #ffffff; + margin: 0 0 15px 0; + text-align: center; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +/* Selection Boxes */ +.selection-box { + border: 1px solid #444; + border-radius: 6px; + padding: 15px; + margin-bottom: 15px; + background-color: #2d2d2d; +} + +/* Default Compiler Row */ +#defaultCompilerRow { + display: flex; + align-items: center; + justify-content: space-between; +} +#defaultCompilerRow .toggle-label { + margin: 0; + color: #fff; + font-weight: 600; +} +#defaultCFGPath { + display: block; + margin-top: 4px; + font-size: 12px; + color: #888; + font-weight: 400; + word-break: break-all; +} + +/* OR Separator */ +#orSeparator { + text-align: center; + margin: 10px 0; +} +#orSeparator h3 { + font-size: 14px; + color: #ffffff; + font-weight: 700; + margin: 0; + text-transform: none; +} + +/* New Compiler Section */ +#newCompilerSection { + display: block; +} + +/* SUB-SECTION TITLE (Configuration Options) */ +.config-options-wrapper { + margin-top: 20px; + padding-top: 15px; + border-top: 1px dashed #444; +} + +.config-options-wrapper h4 { + font-size: 14px; + color: #ffffff; + font-weight: 700; + margin-bottom: 12px; + display: block; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +/* Option Rows */ +.option-row { + display: flex; + align-items: center; + justify-content: space-between; + padding: 8px 0; + width: 100%; +} + +.option-row .toggle-label { + font-size: 14px; + color: #d4d4d4; + font-weight: 400; + margin-bottom: 0; +} + +/* Toggle Switch */ +.vscode-toggle { + display: inline-block; + cursor: pointer; +} +.toggle-switch { + display: inline-block; + position: relative; + width: 40px; + height: 20px; + vertical-align: middle; +} +.toggle-switch input { + opacity: 0; + width: 0; + height: 0; +} +.toggle-switch .slider { + position: absolute; + inset: 0; + background: #3c3c3c; + border: 1px solid #555; + border-radius: 10px; + transition: .2s; +} +.toggle-switch .slider::before { + content: ""; + position: absolute; + height: 16px; + width: 16px; + left: 2px; + bottom: 1px; + background-color: #ccc; + border-radius: 50%; + transition: .2s; +} +.toggle-switch input:checked + .slider { + background-color: #007acc; + border-color: #007acc; +} +.toggle-switch input:checked + .slider::before { + transform: translateX(20px); + background-color: white; +} +.vscode-toggle:hover .slider { + border-color: #666; +} + +/* Buttons */ .button-container { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; + padding-top: 10px; } -/* Primary & cancel buttons */ .primary-button, .cancel-button { - padding: 10px 20px; - font-size: 16px; + padding: 8px 24px; + font-size: 14px; + font-weight: 600; border: none; border-radius: 4px; cursor: pointer; - transition: background-color 0.3s; + transition: background-color 0.2s; } .primary-button { background-color: #007acc; color: white; } - -.primary-button:hover { - background-color: #005f99; -} +.primary-button:hover { background-color: #005f99; } .cancel-button { background-color: #cc4444; color: white; } - .cancel-button:hover { background-color: #992222; -} +} \ No newline at end of file diff --git a/src/manage/webviews/html/newCFG.html b/src/manage/webviews/html/newCFG.html new file mode 100644 index 00000000..67d63cf7 --- /dev/null +++ b/src/manage/webviews/html/newCFG.html @@ -0,0 +1,69 @@ + + + + + + Create New CFG File + + + + + + + {{ compilerDataScript }} + + + + \ No newline at end of file diff --git a/src/manage/webviews/html/newProject.html b/src/manage/webviews/html/newProject.html index d5937b84..60097c1b 100644 --- a/src/manage/webviews/html/newProject.html +++ b/src/manage/webviews/html/newProject.html @@ -25,10 +25,86 @@

Create New Project

- -
- -
    +
    +

    Compiler Selection

    + + + + + + + + +
    + + +
    + +
    + +
      +
      +
      + + +
      +

      Configuration Options:

      + +
      + + +
      + +
      + + +
      + + + + +
      +
      diff --git a/src/manage/webviews/webviewScripts/newCFG.js b/src/manage/webviews/webviewScripts/newCFG.js new file mode 100644 index 00000000..fea04f9a --- /dev/null +++ b/src/manage/webviews/webviewScripts/newCFG.js @@ -0,0 +1,112 @@ +const vscode = acquireVsCodeApi(); + +globalThis.addEventListener("DOMContentLoaded", () => { + const compilers = globalThis.compilerData || []; + const defaultDB = globalThis.defaultDB || ""; + + const compInput = document.getElementById("compilerInput"); + const suggestions = document.getElementById("suggestions"); + + // Toggle checkboxes + const codedCheckbox = document.getElementById("enableCodedTests"); + const defaultCheckbox = document.getElementById("defaultCFG"); + + // DB Elements + const dbOptionRow = document.getElementById("dbOptionRow"); + const dbPathLabel = document.getElementById("dbPathLabel"); + const dbCheckbox = document.getElementById("useDefaultDB"); + + // If extension injected defaults, apply them + if (globalThis.enableCodedTests !== undefined && codedCheckbox) { + codedCheckbox.checked = !!globalThis.enableCodedTests; + } + if (globalThis.defaultCFG !== undefined && defaultCheckbox) { + defaultCheckbox.checked = !!globalThis.defaultCFG; + } + + // --- DB Toggle Visibility Logic --- + if (defaultDB) { + // Setting exists and file exists -> Show the toggle + dbOptionRow.style.display = "flex"; + dbPathLabel.textContent = defaultDB; + } else { + // Setting empty OR file not found -> Keep hidden + dbOptionRow.style.display = "none"; + } + + // Autocomplete setup + let filtered = [], activeIndex = -1; + + function renderSuggestions() { + suggestions.innerHTML = ""; + if (!filtered.length) return suggestions.classList.remove("visible"); + + filtered.forEach((item, i) => { + const li = document.createElement("li"); + li.textContent = item; + if (i === activeIndex) li.classList.add("active"); + li.addEventListener("mousedown", () => { + compInput.value = item; + suggestions.classList.remove("visible"); + }); + suggestions.appendChild(li); + }); + + suggestions.classList.add("visible"); + } + + function updateSuggestions(showAll = false) { + const q = (compInput.value || "").toLowerCase().trim(); + filtered = showAll || !q + ? [...compilers] + : compilers.filter(c => c.toLowerCase().includes(q)); + activeIndex = -1; + renderSuggestions(); + } + + compInput.addEventListener("input", () => updateSuggestions()); + compInput.addEventListener("focus", () => updateSuggestions(true)); + + compInput.addEventListener("keydown", e => { + if (!filtered.length) return; + + if (e.key === "ArrowDown") { + e.preventDefault(); + activeIndex = (activeIndex + 1) % filtered.length; + renderSuggestions(); + } else if (e.key === "ArrowUp") { + e.preventDefault(); + activeIndex = (activeIndex - 1 + filtered.length) % filtered.length; + renderSuggestions(); + } else if (e.key === "Enter") { + e.preventDefault(); + if (filtered[activeIndex]) { + compInput.value = filtered[activeIndex]; + suggestions.classList.remove("visible"); + } + } else if (e.key === "Escape") { + suggestions.classList.remove("visible"); + } + }); + + document.addEventListener("click", e => { + if (!e.target.closest(".autocomplete")) suggestions.classList.remove("visible"); + }); + + // Submit button + document.getElementById("btnSubmit").addEventListener("click", () => { + vscode.postMessage({ + command: "submit", + compilerName: (compInput.value || "").trim(), + // Toggle Values + enableCodedTests: !!(codedCheckbox && codedCheckbox.checked), + defaultCFG: !!(defaultCheckbox && defaultCheckbox.checked), + useDefaultDB: !!(dbCheckbox && dbCheckbox.checked) + }); + }); + + // Cancel button + document.getElementById("btnCancel").addEventListener("click", () => { + vscode.postMessage({ command: "cancel" }); + }); +}); \ No newline at end of file diff --git a/src/manage/webviews/webviewScripts/newProject.js b/src/manage/webviews/webviewScripts/newProject.js index ce7abfeb..c0ac067b 100644 --- a/src/manage/webviews/webviewScripts/newProject.js +++ b/src/manage/webviews/webviewScripts/newProject.js @@ -1,26 +1,76 @@ const vscode = acquireVsCodeApi(); -window.addEventListener("DOMContentLoaded", () => { - const compilers = window.compilerData || []; - const defaultDir = window.defaultDir || ""; +globalThis.addEventListener("DOMContentLoaded", () => { + const compilers = globalThis.compilerData || []; + const defaultCFG = globalThis.defaultCFG || ""; + const defaultDB = globalThis.defaultDB || ""; + + // DOM Elements + const defaultRow = document.getElementById("defaultCompilerRow"); + const defaultPath = document.getElementById("defaultCFGPath"); + const orSeparator = document.getElementById("orSeparator"); + const useDefaultCheckbox = document.getElementById("useDefaultCompiler"); + const newCompilerSection = document.getElementById("newCompilerSection"); const targetInput = document.getElementById("targetDirInput"); - const browseBtn = document.getElementById("btnBrowse"); - const nameInput = document.getElementById("projectNameInput"); - const compInput = document.getElementById("compilerInput"); + const browseBtn = document.getElementById("btnBrowse"); + const nameInput = document.getElementById("projectNameInput"); + const compInput = document.getElementById("compilerInput"); const suggestions = document.getElementById("suggestions"); - // initialize target folder - let targetDir = defaultDir; - targetInput.value = targetDir; + // CFG Option Checkboxes + const codedCheckbox = document.getElementById("enableCodedTests"); + const defaultCFGCheckbox = document.getElementById("defaultCFG"); + + // DB Option Elements + const dbOptionRow = document.getElementById("dbOptionRow"); + const dbPathLabel = document.getElementById("dbPathLabel"); + const dbCheckbox = document.getElementById("useDefaultDB"); + + // --- Initialization Logic --- + + // Show default CFG row + OR only if defaultCFG exists + if (defaultCFG) { + defaultRow.style.display = "flex"; + orSeparator.style.display = "block"; + defaultPath.textContent = defaultCFG; + } else { + defaultRow.style.display = "none"; + orSeparator.style.display = "none"; + } + + // Show Default DB row if a valid path exists + if (defaultDB) { + dbOptionRow.style.display = "flex"; + dbPathLabel.textContent = defaultDB; + } else { + dbOptionRow.style.display = "none"; + } + + function updateCompilerVisibility() { + if (useDefaultCheckbox && useDefaultCheckbox.checked) { + newCompilerSection.style.display = "none"; + if (defaultCFG) orSeparator.style.display = "none"; + } else { + newCompilerSection.style.display = "block"; + if (defaultCFG) orSeparator.style.display = "block"; + } + } + + if (useDefaultCheckbox) { + useDefaultCheckbox.addEventListener("change", updateCompilerVisibility); + } + updateCompilerVisibility(); - // browse for folder + // --- Target Directory Logic --- + let targetDir = globalThis.defaultDir || ""; + targetInput.value = targetDir; + browseBtn.addEventListener("click", () => { vscode.postMessage({ command: "browseForDir" }); }); - - // receive chosen folder - window.addEventListener("message", (e) => { + + globalThis.addEventListener("message", (e) => { const msg = e.data; if (msg.command === "setTargetDir") { targetDir = msg.targetDir; @@ -28,11 +78,13 @@ window.addEventListener("DOMContentLoaded", () => { } }); - // autocomplete setup (unchanged)... + // --- Autocomplete Logic --- let filtered = [], activeIndex = -1; + function renderSuggestions() { suggestions.innerHTML = ""; if (!filtered.length) return suggestions.classList.remove("visible"); + filtered.forEach((item, i) => { const li = document.createElement("li"); li.textContent = item; @@ -45,16 +97,20 @@ window.addEventListener("DOMContentLoaded", () => { }); suggestions.classList.add("visible"); } + function updateSuggestions(showAll = false) { - const q = compInput.value.toLowerCase().trim(); + const q = (compInput.value || "").toLowerCase().trim(); filtered = showAll || !q ? [...compilers] : compilers.filter(c => c.toLowerCase().includes(q)); activeIndex = -1; renderSuggestions(); } + compInput.addEventListener("input", () => updateSuggestions()); compInput.addEventListener("focus", () => updateSuggestions(true)); + compInput.addEventListener("click", () => updateSuggestions(true)); // Ensure click triggers it + compInput.addEventListener("keydown", e => { if (!filtered.length) return; if (e.key === "ArrowDown") { @@ -75,21 +131,30 @@ window.addEventListener("DOMContentLoaded", () => { suggestions.classList.remove("visible"); } }); + document.addEventListener("click", e => { if (!e.target.closest(".autocomplete")) suggestions.classList.remove("visible"); }); - // submit + // --- Submit Logic --- document.getElementById("btnSubmit").addEventListener("click", () => { + const isUsingDefault = useDefaultCheckbox && useDefaultCheckbox.checked; + vscode.postMessage({ command: "submit", projectName: nameInput.value.trim(), - compilerName: compInput.value.trim(), - targetDir + targetDir, + useDefaultCFG: isUsingDefault, + // Send compiler name only if NOT using default CFG + compilerName: isUsingDefault ? undefined : compInput.value.trim(), + // Send compiler options + enableCodedTests: !!(codedCheckbox && codedCheckbox.checked), + defaultCFG: !!(defaultCFGCheckbox && defaultCFGCheckbox.checked), + useDefaultDB: !!(dbCheckbox && dbCheckbox.checked) }); }); - // cancel + // --- Cancel Logic --- document.getElementById("btnCancel").addEventListener("click", () => { vscode.postMessage({ command: "cancel" }); }); diff --git a/src/vcastTestInterface.ts b/src/vcastTestInterface.ts index bf107ad5..7bc4df9a 100644 --- a/src/vcastTestInterface.ts +++ b/src/vcastTestInterface.ts @@ -58,9 +58,13 @@ import { commandStatusType, executeCommandSync, executeVPythonScript, + executeWithRealTimeEchoWithProgress, } from "./vcastCommandRunner"; -import { checksumCommandToUse } from "./vcastInstallation"; +import { + checksumCommandToUse, + getVectorCastInstallationLocation, +} from "./vcastInstallation"; import { closeAnyOpenErrorFiles, @@ -71,6 +75,7 @@ import { closeConnection, globalEnviroDataServerActive, } from "../src-common/vcastServer"; +import { createNewCFGFromCompiler } from "./manage/manageSrc/manageUtils"; const fs = require("fs"); const path = require("path"); @@ -1197,3 +1202,160 @@ export async function getMCDCResultFile( return resultFile; } + +/** + * Updates databaseLocation setting + * @param vcShellPath Path to the defaultV VCDB + */ +export async function updateVCShellDatabase(vcShellPath: string) { + // Update Settings + const settings = vscode.workspace.getConfiguration("vectorcastTestExplorer"); + settings.update("databaseLocation", vcShellPath); + + vscode.window.showInformationMessage( + `Default Database location has been set to: ${vcShellPath}` + ); +} + +/** + * Updates CFG VCDB_FILENAME option + * @param vcShellPath Path of the vcshell db + * @param normalizedCFGPath Path to CFG + */ +export async function updateCFGWithVCShellDatabase( + vcShellPath: string, + normalizedCFGPath: string +) { + // Retrieve VectorCAST Dir + const vcDir = getVectorCastInstallationLocation(); + if (!vcDir) { + vectorMessage("VectorCAST Installation Location not found. Aborting."); + vscode.window.showWarningMessage( + `VectorCAST Installation Location not found. Aborting.` + ); + return; + } + + // Build paths + const vcShellCommand = path.join(normalizePath(vcDir), `clicast`); + const commandToRun = `${vcShellCommand}`; + const fileName = path.basename(vcShellPath); + const normalizedVCShellPath = normalizePath(vcShellPath); + const normalizedCFGDir = normalizePath(path.dirname(normalizedCFGPath)); + + // Execute + const infoMessage = `Loading VectorCAST database from ${fileName} and setting it as the active VCDB.`; + await executeWithRealTimeEchoWithProgress( + commandToRun, + [ + "-lc", + "option", + "VCDB_FILENAME", + `$(readlink -f ${normalizedVCShellPath})`, + ], + normalizedCFGDir, + infoMessage + ); +} + +export interface ConfigurationOptions { + enableCodedTests: boolean; + defaultCFG: boolean; + useDefaultDB: boolean; +} + +/** + * Creates new CFG including selected options like: Default CFG, Enable Coded Tests + * @param workspaceRoot Root of Workspace + * @param compilerTag Compiler name + * @param configurationOptions Additional CFG options + */ +export async function createNewCFGFile( + workspaceRoot: string, + compilerTag: string, + configurationOptions: ConfigurationOptions +) { + const unitTestLocation = getUnitTestLocationForPath(workspaceRoot); + const vcDir = getVectorCastInstallationLocation(); + const commandToRun = path.join(vcDir, "clicast"); + + // Should not happen as we would get that message when initializing the extension, but to be sure + if (!vcDir) { + vectorMessage( + `Could not find VectorCAST Installation Location. Aborting creating a new CFG.` + ); + return; + } + + // Check if a CFG already exists + const cfgFile = path.join(unitTestLocation, "CCAST_.CFG"); + if (fs.existsSync(cfgFile)) { + const choice = await vscode.window.showInformationMessage( + "A CFG file already exists at this location. Do you want to overwrite it?", + "Yes", + "Cancel" + ); + + if (choice !== "Yes") { + vscode.window.showInformationMessage( + `Operation cancelled. Existing CFG ( ${cfgFile} ) was not overwritten.` + ); + return; + } + } + + // First create new CFG and return path + const compilerPath = await createNewCFGFromCompiler( + compilerTag, + unitTestLocation + ); + + // Set Coded Tests option + let codedFlag = "FALSE"; + if (configurationOptions.enableCodedTests) { + codedFlag = "TRUE"; + } + + const codedOptionArgs = [ + "-lc", + "option", + "VCAST_CODED_TESTS_SUPPORT", + codedFlag, + ]; + const codedOptionInfoMessage = + "Setting VCAST_CODED_TESTS_SUPPORT in CFG File"; + await executeWithRealTimeEchoWithProgress( + commandToRun, + codedOptionArgs, + unitTestLocation, + codedOptionInfoMessage + ); + + // Set as Default CFG if required + if (configurationOptions.defaultCFG) { + const settings = vscode.workspace.getConfiguration( + "vectorcastTestExplorer" + ); + settings.update( + "configurationLocation", + compilerPath, + vscode.ConfigurationTarget.Workspace + ); + } + + // Apply Default Database if requested and path exists + if (configurationOptions.useDefaultDB && compilerPath) { + const settings = vscode.workspace.getConfiguration( + "vectorcastTestExplorer" + ); + const dbPath = settings.get("databaseLocation"); + + if (dbPath && fs.existsSync(dbPath)) { + await updateCFGWithVCShellDatabase(dbPath, compilerPath); + } else { + vscode.window.showWarningMessage( + "Could not set Default Database: The database file defined in settings could not be found." + ); + } + } +} diff --git a/tests/internal/e2e/test/manage/tutorial/CCAST_.CFG b/tests/internal/e2e/test/manage/tutorial/CCAST_.CFG new file mode 100644 index 00000000..ccc701a8 --- /dev/null +++ b/tests/internal/e2e/test/manage/tutorial/CCAST_.CFG @@ -0,0 +1,2 @@ +VCAST_DISPLAY_UNINST_EXPR: FALSE +VCAST_REPOSITORY: /home/denis/VectorCAST/vcshell_implementation/tests/internal/e2e/test/vcastTutorial diff --git a/tests/internal/e2e/test/manage/tutorial/vcshell.db b/tests/internal/e2e/test/manage/tutorial/vcshell.db new file mode 100644 index 00000000..34ef56ad Binary files /dev/null and b/tests/internal/e2e/test/manage/tutorial/vcshell.db differ diff --git a/tests/internal/e2e/test/specs/vcast_manage.test.ts b/tests/internal/e2e/test/specs/vcast_manage.test.ts index 0b462eec..abad371f 100644 --- a/tests/internal/e2e/test/specs/vcast_manage.test.ts +++ b/tests/internal/e2e/test/specs/vcast_manage.test.ts @@ -137,7 +137,7 @@ describe("vTypeCheck VS Code Extension", () => { const notificationsCenter = await workbench.openNotificationsCenter(); await notificationsCenter.clearAllNotifications(); - console.log("Executing Create New Project Command:"); + console.log("Executing Create New Project Command (with options = false):"); await browser.executeWorkbench((vscode) => { vscode.commands.executeCommand("vectorcastTestExplorer.createNewProject"); }); @@ -151,13 +151,23 @@ describe("vTypeCheck VS Code Extension", () => { await browser.keys("GNU Native_Automatic_C++17"); await browser.keys(["Tab"]); await browser.keys(["Tab"]); + await browser.keys(["Tab"]); + await browser.keys(["Tab"]); await browser.keys(["Enter"]); await browser.waitUntil( async () => (await outputView.getText()) .toString() - .includes(`Added Compiler CCAST_.CFG to Project ANewProject`), + .includes(`-lc option VCAST_CODED_TESTS_SUPPORT FALSE`), + { timeout: TIMEOUT } + ); + + await browser.waitUntil( + async () => + (await outputView.getText()) + .toString() + .includes(`Processing project: ANewProject`), { timeout: TIMEOUT } ); @@ -171,6 +181,130 @@ describe("vTypeCheck VS Code Extension", () => { expect(compilerNode).toBeDefined(); }); + it("testing setting default vcshell.db", async () => { + await updateTestID(); + await bottomBar.toggle(true); + const outputView = await bottomBar.openOutputView(); + await outputView.clearText(); + + const workbench = await browser.getWorkbench(); + const activityBar = workbench.getActivityBar(); + const explorerView = await activityBar.getViewControl("Explorer"); + await explorerView?.openView(); + + const workspaceFolderSection = + await expandWorkspaceFolderSectionInExplorer("vcastTutorial"); + const vcshellFolder = workspaceFolderSection.findItem("tutorial"); + await (await vcshellFolder).select(); + + console.log("Selecting vcshell.db"); + const vcshell = await workspaceFolderSection.findItem("vcshell.db"); + await executeCtrlClickOn(vcshell); + await releaseCtrl(); + console.log("Executing: Set as default Database"); + await vcshell.openContextMenu(); + await (await $("aria/Set as default Database")).click(); + + console.log("Checking whetehr Setting got updated"); + const settingsEditor = await workbench.openSettings(); + + // Switch scope to Workspace + await (await $("aria/Workspace")).click(); + + const databaseLocationSetting = await settingsEditor.findSetting( + "Database Location", + "Vectorcast Test Explorer" + ); + + const locationValue = await databaseLocationSetting.getValue(); + console.log(`Location Value: ${locationValue}`); + expect(locationValue).toBeDefined(); + }); + + it("testing creating second project 'Banana'", async () => { + await updateTestID(); + await bottomBar.toggle(true); + const outputView = await bottomBar.openOutputView(); + await outputView.clearText(); + + const notificationsCenter = await workbench.openNotificationsCenter(); + await notificationsCenter.clearAllNotifications(); + + console.log("Executing Create New Project Command for Banana:"); + await browser.executeWorkbench((vscode) => { + vscode.commands.executeCommand("vectorcastTestExplorer.createNewProject"); + }); + + console.log("Inserting Data to Webview for Banana project"); + await insertStringToInput("Banana", "Project Name Input"); + await browser.keys(["Tab"]); + await browser.keys("GNU Native_Automatic_C++"); + // Toggle "Enable Coded Tests" ON + await browser.keys(["Tab"]); + await browser.keys([" "]); + // Toggle "Set as Default CFG" ON + await browser.keys(["Tab"]); + await browser.keys([" "]); + // Toggle vcshell.db option ON + await browser.keys(["Tab"]); + await browser.keys([" "]); + await browser.keys(["Tab"]); + await browser.keys(["Tab"]); + await browser.keys(["Enter"]); + + console.log("Verifying Coded Tests Support is set to True"); + await browser.waitUntil( + async () => + (await outputView.getText()) + .toString() + .includes(`-lc option VCAST_CODED_TESTS_SUPPORT TRUE`), + { timeout: TIMEOUT } + ); + + await browser.waitUntil( + async () => { + const output = (await outputView.getText()).toString(); + return ( + output.includes("clicast: '-lc option VCDB_FILENAME") && + output.includes("vcshell.db)' returned exit code: 0") + ); + }, + { timeout: TIMEOUT } + ); + + await browser.waitUntil( + async () => + (await outputView.getText()) + .toString() + .includes(`Processing project: Banana`), + { timeout: TIMEOUT } + ); + + console.log("Checking existence of Banana Project"); + const projectNode = await findTreeNodeAtLevel(0, "Banana.vcm"); + const compilerNode = await findTreeNodeAtLevel( + 1, + "GNU_Native_Automatic_C++" + ); + expect(projectNode).toBeDefined(); + expect(compilerNode).toBeDefined(); + + console.log( + "Verifying configurationLocation setting ends with Banana/CCAST.CFG" + ); + const configLocation = await browser.executeWorkbench((vscode) => { + return vscode.workspace + .getConfiguration("vectorcastTestExplorer") + .get("configurationLocation"); + }); + + console.log(`Configuration location: ${configLocation}`); + expect(configLocation).toBeDefined(); + + // Check if config location is set with the new CFG from the project + expect(configLocation.endsWith("Banana/CCAST_.CFG")).toBe(true); + }); + it("testing tree structure", async () => { await updateTestID(); @@ -493,6 +627,7 @@ describe("vTypeCheck VS Code Extension", () => { // CLose Report again await webview.close(); await editorView.closeEditor("VectorCAST Report", 1); + await workbench.getEditorView().closeAllEditors(); }); it("testing creating a Testsuite", async () => { @@ -578,7 +713,7 @@ describe("vTypeCheck VS Code Extension", () => { expect(testsuiteNode).toBeUndefined(); }); - it("testing deleting a project Environment", async () => { + it("testing cleaning a project Environment", async () => { await updateTestID(); await bottomBar.toggle(true); const outputView = await bottomBar.openOutputView(); @@ -725,7 +860,7 @@ describe("vTypeCheck VS Code Extension", () => { const notificationsCenter = await workbench.openNotificationsCenter(); await notificationsCenter.clearAllNotifications(); - console.log("Deleting Environment QUACK from Project"); + // Trigger the Delete action await executeContextMenuAction( 3, "QUACK", @@ -734,13 +869,25 @@ describe("vTypeCheck VS Code Extension", () => { ); console.log("Confirming Notifications to delete the Environment"); - const notifications = await $("aria/Notifications"); - await notifications.click(); - const vcastNotificationSourceElement = await $( - "aria/VectorCAST Test Explorer (Extension)" - ); - const vcastNotification = await vcastNotificationSourceElement.$(".."); - await (await vcastNotification.$("aria/Delete")).click(); + + // Wait for the notification to be generated (exist in DOM) + const vcastNotificationSelector = + "aria/VectorCAST Test Explorer (Extension)"; + const pendingNotification = await $(vcastNotificationSelector); + await browser.takeScreenshot(); + await browser.saveScreenshot("info_clicked_on_delete.png"); + + // Navigate to the Delete button + const vcastNotification = await $(vcastNotificationSelector).$(".."); + const deleteAction = await vcastNotification.$("aria/Delete"); + + // Wait for the button to be Clickable (handles animation/obscuring) + await deleteAction.waitForClickable({ + timeout: TIMEOUT, + timeoutMsg: "Delete button in notification was not interactable", + }); + + await deleteAction.click(); console.log("Checking for Output logs if Environment deletion is finished"); await browser.waitUntil( @@ -790,8 +937,6 @@ describe("vTypeCheck VS Code Extension", () => { const workspaceFolderSection = await expandWorkspaceFolderSectionInExplorer("vcastTutorial"); - const cppFolder = workspaceFolderSection.findItem("tutorial"); - await (await cppFolder).select(); console.log("Selecting database.cpp & manager.cpp"); const managerCpp = await workspaceFolderSection.findItem("manager.cpp");