From e257c5a3dc476d7bf837827fd8f33bcfbfce122f Mon Sep 17 00:00:00 2001 From: Den1552 Date: Wed, 10 Dec 2025 16:29:02 +0100 Subject: [PATCH 01/26] Initial C Cov commit --- package.json | 3 +- python/mcdcReport.py | 37 ++++++++++++++++++++++--- python/vTestInterface.py | 54 ++++++++++++++++++++++++++++++++++-- src/editorDecorator.ts | 6 +++- src/extension.ts | 11 ++++++-- src/testData.ts | 1 + src/testPane.ts | 58 +++++++++++++++++++++++++++++++++++---- src/utilities.ts | 4 ++- src/vcastTestInterface.ts | 5 +++- src/vcastUtilities.ts | 9 +++--- 10 files changed, 165 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index cee14e70..ae6b7c26 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,8 @@ "main": "out/extension.js", "activationEvents": [ "workspaceContains:**/UNITDATA.VCD", - "workspaceContains:**/*.vcm" + "workspaceContains:**/*.vcm", + "workspaceContains:**/*.vcp" ], "contributes": { "viewsWelcome": [ diff --git a/python/mcdcReport.py b/python/mcdcReport.py index 3c632695..6df02d13 100644 --- a/python/mcdcReport.py +++ b/python/mcdcReport.py @@ -1,8 +1,10 @@ import argparse import pathlib import sys +import os from vector.apps.DataAPI.unit_test_api import UnitTestApi +from vector.apps.DataAPI.cover_api import CoverApi from pythonUtilities import monkeypatch_custom_css @@ -29,11 +31,35 @@ def parse_args(): return parser.parse_args() +def get_api_context(env_path): + """ + Determines if the environment is a Cover Project or a standard Unit Test env. + Returns: (ApiClass, collection_name, path_to_use) + """ + clean_path = os.path.normpath(env_path) + + # CASE 1: The user provided the path to the .vcp file directly + if clean_path.lower().endswith(".vcp") and os.path.isfile(clean_path): + return CoverApi, "File" + + # CASE 2: The user provided a folder (e.g. /path/to/env) + # but the VCP file is adjacent (/path/to/env.vcp) + sibling_vcp = clean_path + ".vcp" + if os.path.isfile(sibling_vcp): + return CoverApi, "File" + + # CASE 3: Standard Unit Test Environment (The folder itself) + return UnitTestApi, "Unit" + + def get_mcdc_lines(env): all_lines_with_data = {} - with UnitTestApi(env) as api: - for unit in api.Unit.filter(): + ApiClass, collection_name = get_api_context(env) + + with ApiClass(env) as api: + collection = getattr(api, collection_name) + for unit in collection.filter(): for mcdc_dec in unit.cover_data.mcdc_decisions: if not mcdc_dec.num_conditions: continue @@ -63,11 +89,14 @@ def generate_mcdc_report(env, unit_filter, line_filter, output): # Patch get_option to use our CSS without setting the CFG option monkeypatch_custom_css(custom_css) + ApiClass, collection_name = get_api_context(env) + # Open-up the unit test API - with UnitTestApi(env) as api: + with ApiClass(env) as api: + collection = getattr(api, collection_name) # Find and check for our unit unit_found = False - for unit in api.Unit.filter(name=unit_filter): + for unit in collection.filter(name=unit_filter): unit_found = True # Spin through all MCDC decisions looking for the one on our line diff --git a/python/vTestInterface.py b/python/vTestInterface.py index c9b54c0c..10670de7 100644 --- a/python/vTestInterface.py +++ b/python/vTestInterface.py @@ -36,6 +36,7 @@ from vector.apps.DataAPI.manage_api import VCProjectApi from vector.apps.DataAPI.vcproject_models import EnvironmentType from vector.apps.DataAPI.unit_test_api import UnitTestApi +from vector.apps.DataAPI.cover_api import CoverApi from vector.lib.core.system import cd from vector.enums import COVERAGE_TYPE_TYPE_T @@ -413,6 +414,9 @@ def getCoverageData(sourceObject): checksum = sourceObject.checksum coverageKind = getCoverageKind(sourceObject) + # print("----------------") + # print(coverageKind) + # print("----------------") mcdc_line_dic = coverageGutter.getMCDCLineDic(sourceObject) # iterate_coverage crashes if the file path doesn't exist if os.path.exists(sourceObject.path): @@ -735,6 +739,21 @@ def scan_dir(path): return vce_files +def find_vcp_files(root_dir): + vce_files = [] + + def scan_dir(path): + with os.scandir(path) as entries: + for entry in entries: + if entry.is_file() and entry.name.endswith(".vcp"): + vce_files.append(entry.path) + elif entry.is_dir(follow_symlinks=False): + scan_dir(entry.path) + + scan_dir(root_dir) + return vce_files + + def processCommandLogic(mode, clicast, pathToUse, testString="", options=""): """ This function does the actual work of processing a vTestInterface command, @@ -780,10 +799,12 @@ def processCommandLogic(mode, clicast, pathToUse, testString="", options=""): elif mode == "getWorkspaceEnviroData": enviro_list = [] + vcp_list = [] errors = [] topLevel = {} - vce_files = find_vce_files(pathToUse) + # 1. Process VCE (Unit Test) Files + vce_files = find_vce_files(pathToUse) for vce_path in vce_files: try: api = UnitTestApi(vce_path) @@ -800,13 +821,42 @@ def processCommandLogic(mode, clicast, pathToUse, testString="", options=""): "mockingSupport": mocking_support, } ) - except Exception as err: errors.append(f"{vce_path}: {str(err)}") + # 2. Process VCP (Cover) Files + vcp_files = find_vcp_files(pathToUse) + for vcp_path in vcp_files: + try: + api = CoverApi(vcp_path) + test_data = [] # Cover projects do not have test data + unit_data = getUnitData(api) + mocking_support = False # Cover projects do not support mocking + api.close() + + vcp_list.append( + { + "vcpPath": normalize_path(vcp_path), + "testData": test_data, + "unitData": unit_data, + "mockingSupport": mocking_support, + } + ) + except Exception as err: + errors.append(f"{vcp_path}: {str(err)}") + + # 3. Construct Top Level Object + # Defaulting top-level data to the first VCE environment found (if any) topLevel["testData"] = enviro_list[0]["testData"] if enviro_list else [] topLevel["unitData"] = enviro_list[0]["unitData"] if enviro_list else [] + + # If no VCEs exist but VCPs do, you might want to fallback to VCP unitData: + if not topLevel["unitData"] and vcp_list: + topLevel["unitData"] = vcp_list[0]["unitData"] + topLevel["enviro"] = enviro_list + topLevel["vcp"] = vcp_list + if errors: topLevel["errors"] = errors diff --git a/src/editorDecorator.ts b/src/editorDecorator.ts index 9719e6a0..094d45ba 100644 --- a/src/editorDecorator.ts +++ b/src/editorDecorator.ts @@ -37,7 +37,11 @@ export async function updateCurrentActiveUnitMCDCLines() { // Get the unit name based on the file name without extension const fullPath = activeEditor.document.fileName; - const unitName = path.basename(fullPath, path.extname(fullPath)); + let unitName = path.basename(fullPath, path.extname(fullPath)); + + if (enviroPath?.endsWith(".vcp")) { + unitName = unitName + path.extname(fullPath); + } // Get all mcdc lines for every unit and parse it into JSON if (enviroPath) { diff --git a/src/extension.ts b/src/extension.ts index 1caa308f..fa25450a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1221,8 +1221,15 @@ function configureExtension(context: vscode.ExtensionContext) { const filePath = activeEditor ? activeEditor.document.uri.fsPath : fileFromUri; - const enviroPath = getEnvPathForFilePath(filePath); - const fileName = path.parse(filePath).name; + let enviroPath = getEnvPathForFilePath(filePath); + let fileName = path.parse(filePath).name; + + if (enviroPath?.endsWith(".vcp")) { + fileName = fileName + path.extname(filePath); + const parsed = path.parse(enviroPath); + enviroPath = path.join(parsed.dir, parsed.name); + } + if (enviroPath) { viewMCDCReport(enviroPath, fileName, args.lineNumber); } else { diff --git a/src/testData.ts b/src/testData.ts index d1d01b1d..178e93a0 100644 --- a/src/testData.ts +++ b/src/testData.ts @@ -1,6 +1,7 @@ import { normalizePath, quote } from "./utilities"; export interface environmentNodeDataType { + isVcp: boolean; projectPath: string; buildDirectory: string; isBuilt: boolean; diff --git a/src/testPane.ts b/src/testPane.ts index 2fe7dfaf..bc40fe11 100644 --- a/src/testPane.ts +++ b/src/testPane.ts @@ -135,6 +135,7 @@ type UnitData = { type EnviroData = { vcePath: string; + vcpPath: string; testData: FileTestData[]; unitData: UnitData[]; mockingSupport: boolean; @@ -144,6 +145,7 @@ type CachedWorkspaceData = { testData: FileTestData[]; unitData: UnitData[]; enviro: EnviroData[]; + vcp: EnviroData[]; errors?: string[]; }; @@ -630,6 +632,35 @@ export function addFreeEnvironments( } } +/** + * Adds VCP (VectorCAST Cover Project) files found in the workspace cache to the environment list. + * These are treated as environments but will have no test children. + * @param environmentList A list to push environment data. + * @param workspaceRoot The workspace root directory path. + */ +export function addVcpEnvironments( + environmentList: any[], + workspaceRoot: string +): void { + // Check if the cached data exists and has the 'vcp' key we added in Python + if (cachedWorkspaceEnvData && cachedWorkspaceEnvData.vcp) { + for (const vcpData of cachedWorkspaceEnvData.vcp) { + // vcpData contains: { vcpPath, testData (empty), unitData, mockingSupport } + const normalizedPath = normalizePath(vcpData.vcpPath); + const displayName = path.basename(normalizedPath); + + environmentList.push({ + projectPath: "", // VCPs are usually standalone or treated differently than managed envs + buildDirectory: normalizedPath, // We use the VCP file path as the identifier + isBuilt: true, // VCPs are considered "non-built" / accessible + displayName: displayName, + workspaceRoot: workspaceRoot, + isVcp: true, // Flag to identify this as a VCP node if needed downstream + }); + } + } +} + /** * Checks if the given path is an environment of interest. * @param candidatePath - The path to check @@ -739,17 +770,29 @@ async function loadEnviroData( comingFromRefresh: boolean ): Promise { let buildDirDerivedFromVCEPath: string = ""; + let buildDirDerivedFromVCPPath: string = ""; let buildPathDir: string = enviroData.buildDirectory; if (comingFromRefresh) { // If we've already fetched the full workspace data, reuse it if (cachedWorkspaceEnvData) { - const enviroList = cachedWorkspaceEnvData["enviro"]; - vectorMessage(`Processing environment data for: ${buildPathDir}`); - for (const envAPIData of enviroList) { - buildDirDerivedFromVCEPath = envAPIData.vcePath.split(".vce")[0]; - if (buildDirDerivedFromVCEPath === buildPathDir) { - return envAPIData; + if (enviroData.isVcp) { + const vcpListList = cachedWorkspaceEnvData["vcp"]; + vectorMessage(`Processing coverage project data for: ${buildPathDir}`); + for (const vcpAPIData of vcpListList) { + buildDirDerivedFromVCPPath = vcpAPIData.vcpPath; + if (buildDirDerivedFromVCPPath === buildPathDir) { + return vcpAPIData; + } + } + } else { + const enviroList = cachedWorkspaceEnvData["enviro"]; + vectorMessage(`Processing environment data for: ${buildPathDir}`); + for (const envAPIData of enviroList) { + buildDirDerivedFromVCEPath = envAPIData.vcePath.split(".vce")[0]; + if (buildDirDerivedFromVCEPath === buildPathDir) { + return envAPIData; + } } } } else { @@ -980,6 +1023,9 @@ async function loadAllVCTests( ignoreEnvsInProject, environmentList ); + + // Add VCP (Cover Project) files + addVcpEnvironments(environmentList, workspaceRoot); } if (environmentList.length > 0) { diff --git a/src/utilities.ts b/src/utilities.ts index 16d2ab66..2eca5593 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -406,7 +406,9 @@ export async function updateCoverageAndRebuildEnv() { } // Now rebuild every env so that the coverage is updated for (let enviroPath of envArray) { - await rebuildEnvironment(enviroPath, rebuildEnvironmentCallback); + if (!enviroPath.endsWith(".vcp")) { + await rebuildEnvironment(enviroPath, rebuildEnvironmentCallback); + } } } diff --git a/src/vcastTestInterface.ts b/src/vcastTestInterface.ts index bf107ad5..0eb9b215 100644 --- a/src/vcastTestInterface.ts +++ b/src/vcastTestInterface.ts @@ -189,6 +189,7 @@ export function clearTestDataFromStatusArray(): void { // List of source file from all local environments interface coverageDataType { crc32Checksum: number; + isVCP: boolean; covered: number[]; uncovered: number[]; partiallyCovered: number[]; @@ -248,7 +249,7 @@ export function getCoverageDataForFile(filePath: string): coverageSummaryType { let uncoveredList: number[] = []; let partiallyCoveredList: number[] = []; for (const enviroData of dataForThisFile.enviroList.values()) { - if (enviroData.crc32Checksum == checksum) { + if (enviroData.crc32Checksum == checksum || enviroData.isVCP) { coveredList = coveredList.concat(enviroData.covered); uncoveredList = uncoveredList.concat(enviroData.uncovered); partiallyCoveredList = partiallyCoveredList.concat( @@ -338,7 +339,9 @@ export function updateGlobalDataForFile(enviroPath: string, fileList: any[]) { .map(Number); const checksum = fileList[fileIndex].cmcChecksum; + let coverageData: coverageDataType = { + isVCP: enviroPath.endsWith(".vcp"), crc32Checksum: checksum, covered: coveredList, uncovered: uncoveredList, diff --git a/src/vcastUtilities.ts b/src/vcastUtilities.ts index d19f83b0..43fc4a6a 100644 --- a/src/vcastUtilities.ts +++ b/src/vcastUtilities.ts @@ -444,11 +444,10 @@ export function getVcastInterfaceCommandForMCDC( let optionsDict: { [command: string]: string | number } = {}; optionsDict["unitName"] = unitName; optionsDict["lineNumber"] = lineNumber; - const jsonOptions: string = JSON.stringify(optionsDict).replaceAll( - '"', - '\\"' - ); - const testArgument = `--options="${jsonOptions}"`; + + const jsonOptions: string = JSON.stringify(optionsDict); + const testArgument = `--options='${jsonOptions}'`; + return `${commandToRun} ${testArgument}`; } From 5d86103b137d959515af2bcf68bd23d46c1abd87 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Wed, 10 Dec 2025 17:18:31 +0100 Subject: [PATCH 02/26] Switched code to utilities --- python/mcdcReport.py | 27 +++++---------------------- python/pythonUtilities.py | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/python/mcdcReport.py b/python/mcdcReport.py index 6df02d13..09b29b1a 100644 --- a/python/mcdcReport.py +++ b/python/mcdcReport.py @@ -6,7 +6,7 @@ from vector.apps.DataAPI.unit_test_api import UnitTestApi from vector.apps.DataAPI.cover_api import CoverApi -from pythonUtilities import monkeypatch_custom_css +from pythonUtilities import monkeypatch_custom_css, get_api_context def parse_args(): @@ -31,30 +31,11 @@ def parse_args(): return parser.parse_args() -def get_api_context(env_path): - """ - Determines if the environment is a Cover Project or a standard Unit Test env. - Returns: (ApiClass, collection_name, path_to_use) - """ - clean_path = os.path.normpath(env_path) - - # CASE 1: The user provided the path to the .vcp file directly - if clean_path.lower().endswith(".vcp") and os.path.isfile(clean_path): - return CoverApi, "File" - - # CASE 2: The user provided a folder (e.g. /path/to/env) - # but the VCP file is adjacent (/path/to/env.vcp) - sibling_vcp = clean_path + ".vcp" - if os.path.isfile(sibling_vcp): - return CoverApi, "File" - - # CASE 3: Standard Unit Test Environment (The folder itself) - return UnitTestApi, "Unit" - - def get_mcdc_lines(env): all_lines_with_data = {} + # We have to check whether env is the path to a "Normal" env or to a "Cover Project" + # and therefore use a different API ApiClass, collection_name = get_api_context(env) with ApiClass(env) as api: @@ -89,6 +70,8 @@ def generate_mcdc_report(env, unit_filter, line_filter, output): # Patch get_option to use our CSS without setting the CFG option monkeypatch_custom_css(custom_css) + # We have to check whether env is the path to a "Normal" env or to a "Cover Project" + # and therefore use a different API ApiClass, collection_name = get_api_context(env) # Open-up the unit test API diff --git a/python/pythonUtilities.py b/python/pythonUtilities.py index cc70ce89..4c5d1e23 100644 --- a/python/pythonUtilities.py +++ b/python/pythonUtilities.py @@ -233,3 +233,20 @@ def repl(match): return match.group(0) return env_var_pattern.sub(repl, path) + + +def get_api_context(env_path): + """ + Determines if the environment is a Cover Project or a standard Unit Test env. + And returns what API we need to use. + """ + clean_path = os.path.normpath(env_path) + + # Check if it's a Cover project by checking if there is a vcp file + # with the same name on the same level like the build dir (env_path) + vcp_file = clean_path + ".vcp" + if os.path.isfile(vcp_file): + return CoverApi, "File" + + # If there is no vcp file --> normal env + return UnitTestApi, "Unit" From 4063e02e1280e398ef3d4368a5ad4db64e452066 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Wed, 10 Dec 2025 18:19:37 +0100 Subject: [PATCH 03/26] Corrected initial mcdc line fetch --- python/pythonUtilities.py | 4 ++++ src/editorDecorator.ts | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/python/pythonUtilities.py b/python/pythonUtilities.py index 4c5d1e23..7999ea7e 100644 --- a/python/pythonUtilities.py +++ b/python/pythonUtilities.py @@ -6,6 +6,10 @@ import re from vector.apps.DataAPI.configuration import EnvironmentMixin +from vector.apps.DataAPI.unit_test_api import UnitTestApi +from vector.apps.DataAPI.cover_api import CoverApi + + # This contains the clicast command that was used to start the data server globalClicastCommand = "" diff --git a/src/editorDecorator.ts b/src/editorDecorator.ts index 094d45ba..af1ec921 100644 --- a/src/editorDecorator.ts +++ b/src/editorDecorator.ts @@ -33,14 +33,17 @@ export async function updateCurrentActiveUnitMCDCLines() { if (activeEditor) { // First we need to get the env name from the active file const filePath = activeEditor.document.uri.fsPath; - const enviroPath = getEnvPathForFilePath(filePath); + let enviroPath = getEnvPathForFilePath(filePath); // Get the unit name based on the file name without extension const fullPath = activeEditor.document.fileName; let unitName = path.basename(fullPath, path.extname(fullPath)); + // If the file is in a cover project, we need adapt the paths if (enviroPath?.endsWith(".vcp")) { unitName = unitName + path.extname(fullPath); + const parsed = path.parse(enviroPath); + enviroPath = path.join(parsed.dir, parsed.name); } // Get all mcdc lines for every unit and parse it into JSON From ddd2e43e3afb0f6f62b07567708183381f93e463 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Thu, 11 Dec 2025 09:19:03 +0100 Subject: [PATCH 04/26] Removed commented code --- python/vTestInterface.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/python/vTestInterface.py b/python/vTestInterface.py index 10670de7..bd21ea1e 100644 --- a/python/vTestInterface.py +++ b/python/vTestInterface.py @@ -414,9 +414,6 @@ def getCoverageData(sourceObject): checksum = sourceObject.checksum coverageKind = getCoverageKind(sourceObject) - # print("----------------") - # print(coverageKind) - # print("----------------") mcdc_line_dic = coverageGutter.getMCDCLineDic(sourceObject) # iterate_coverage crashes if the file path doesn't exist if os.path.exists(sourceObject.path): From ddce4e078336366aecf0040047a4ee9df3adc1d6 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Thu, 11 Dec 2025 15:27:50 +0100 Subject: [PATCH 05/26] Refactoring --- package.json | 3 ++- python/mcdcReport.py | 17 ++++++++-------- python/vTestInterface.py | 44 +++++++++++++++++----------------------- src/testPane.ts | 4 ++-- 4 files changed, 31 insertions(+), 37 deletions(-) diff --git a/package.json b/package.json index ae6b7c26..6e16d53c 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "activationEvents": [ "workspaceContains:**/UNITDATA.VCD", "workspaceContains:**/*.vcm", - "workspaceContains:**/*.vcp" + "workspaceContains:**/*.vcp", + "workspaceContains:**/*.env" ], "contributes": { "viewsWelcome": [ diff --git a/python/mcdcReport.py b/python/mcdcReport.py index 09b29b1a..1bf364e7 100644 --- a/python/mcdcReport.py +++ b/python/mcdcReport.py @@ -34,13 +34,13 @@ def parse_args(): def get_mcdc_lines(env): all_lines_with_data = {} - # We have to check whether env is the path to a "Normal" env or to a "Cover Project" - # and therefore use a different API - ApiClass, collection_name = get_api_context(env) + ApiClass, entity_attr = get_api_context(env) with ApiClass(env) as api: - collection = getattr(api, collection_name) - for unit in collection.filter(): + # Access the API property (api.Unit or api.File) dynamically + source_modules = getattr(api, entity_attr) + + for unit in source_modules.filter(): for mcdc_dec in unit.cover_data.mcdc_decisions: if not mcdc_dec.num_conditions: continue @@ -72,14 +72,13 @@ def generate_mcdc_report(env, unit_filter, line_filter, output): # We have to check whether env is the path to a "Normal" env or to a "Cover Project" # and therefore use a different API - ApiClass, collection_name = get_api_context(env) + ApiClass, entity_attr = get_api_context(env) - # Open-up the unit test API with ApiClass(env) as api: - collection = getattr(api, collection_name) + source_modules = getattr(api, entity_attr) # Find and check for our unit unit_found = False - for unit in collection.filter(name=unit_filter): + for unit in source_modules.filter(name=unit_filter): unit_found = True # Spin through all MCDC decisions looking for the one on our line diff --git a/python/vTestInterface.py b/python/vTestInterface.py index bd21ea1e..3943a0e9 100644 --- a/python/vTestInterface.py +++ b/python/vTestInterface.py @@ -721,34 +721,28 @@ def getProjectCompilerData(api): return compilerList -def find_vce_files(root_dir): - vce_files = [] - - def scan_dir(path): - with os.scandir(path) as entries: - for entry in entries: - if entry.is_file() and entry.name.endswith(".vce"): - vce_files.append(entry.path) - elif entry.is_dir(follow_symlinks=False): - scan_dir(entry.path) - - scan_dir(root_dir) - return vce_files - - -def find_vcp_files(root_dir): +def find_environment_files(root_dir): + """ + Scans the directory tree once and returns two lists: + 1. vce_files: Paths to vce files for Unit Test environments + 2. vcp_files: Paths to vcp files for Cover Projects + """ vce_files = [] + vcp_files = [] def scan_dir(path): with os.scandir(path) as entries: for entry in entries: - if entry.is_file() and entry.name.endswith(".vcp"): - vce_files.append(entry.path) + if entry.is_file(): + if entry.name.endswith(".vce"): + vce_files.append(entry.path) + elif entry.name.endswith(".vcp"): + vcp_files.append(entry.path) elif entry.is_dir(follow_symlinks=False): scan_dir(entry.path) scan_dir(root_dir) - return vce_files + return vce_files, vcp_files def processCommandLogic(mode, clicast, pathToUse, testString="", options=""): @@ -800,8 +794,10 @@ def processCommandLogic(mode, clicast, pathToUse, testString="", options=""): errors = [] topLevel = {} - # 1. Process VCE (Unit Test) Files - vce_files = find_vce_files(pathToUse) + # Scan directory for both file types + vce_files, vcp_files = find_environment_files(pathToUse) + + # Process VCE Files for vce_path in vce_files: try: api = UnitTestApi(vce_path) @@ -821,8 +817,7 @@ def processCommandLogic(mode, clicast, pathToUse, testString="", options=""): except Exception as err: errors.append(f"{vce_path}: {str(err)}") - # 2. Process VCP (Cover) Files - vcp_files = find_vcp_files(pathToUse) + # Process VCP Files for vcp_path in vcp_files: try: api = CoverApi(vcp_path) @@ -842,12 +837,11 @@ def processCommandLogic(mode, clicast, pathToUse, testString="", options=""): except Exception as err: errors.append(f"{vcp_path}: {str(err)}") - # 3. Construct Top Level Object + # Construct Top Level Object # Defaulting top-level data to the first VCE environment found (if any) topLevel["testData"] = enviro_list[0]["testData"] if enviro_list else [] topLevel["unitData"] = enviro_list[0]["unitData"] if enviro_list else [] - # If no VCEs exist but VCPs do, you might want to fallback to VCP unitData: if not topLevel["unitData"] and vcp_list: topLevel["unitData"] = vcp_list[0]["unitData"] diff --git a/src/testPane.ts b/src/testPane.ts index bc40fe11..e7519e47 100644 --- a/src/testPane.ts +++ b/src/testPane.ts @@ -777,9 +777,9 @@ async function loadEnviroData( // If we've already fetched the full workspace data, reuse it if (cachedWorkspaceEnvData) { if (enviroData.isVcp) { - const vcpListList = cachedWorkspaceEnvData["vcp"]; + const vcpList = cachedWorkspaceEnvData["vcp"]; vectorMessage(`Processing coverage project data for: ${buildPathDir}`); - for (const vcpAPIData of vcpListList) { + for (const vcpAPIData of vcpList) { buildDirDerivedFromVCPPath = vcpAPIData.vcpPath; if (buildDirDerivedFromVCPPath === buildPathDir) { return vcpAPIData; From d8e12fee07e8a15403fe534e112909cc60df478d Mon Sep 17 00:00:00 2001 From: Den1552 Date: Thu, 11 Dec 2025 15:40:44 +0100 Subject: [PATCH 06/26] Refactoring 2 --- src/editorDecorator.ts | 16 ++++++++++------ src/extension.ts | 16 +++++++++------- src/utilities.ts | 22 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/editorDecorator.ts b/src/editorDecorator.ts index af1ec921..275e18bb 100644 --- a/src/editorDecorator.ts +++ b/src/editorDecorator.ts @@ -3,7 +3,11 @@ import { DecorationRenderOptions, TextEditorDecorationType } from "vscode"; import { testNodeType } from "./testData"; -import { getEnvPathForFilePath, getRangeOption } from "./utilities"; +import { + getEnvPathForFilePath, + getRangeOption, + resolveVcpPaths, +} from "./utilities"; import { checksumMatchesEnvironment } from "./vcastTestInterface"; import { getMCDCCoverageLines } from "./vcastAdapter"; @@ -40,11 +44,11 @@ export async function updateCurrentActiveUnitMCDCLines() { let unitName = path.basename(fullPath, path.extname(fullPath)); // If the file is in a cover project, we need adapt the paths - if (enviroPath?.endsWith(".vcp")) { - unitName = unitName + path.extname(fullPath); - const parsed = path.parse(enviroPath); - enviroPath = path.join(parsed.dir, parsed.name); - } + ({ enviroPath, unitName } = resolveVcpPaths( + enviroPath, + unitName, + fullPath + )); // Get all mcdc lines for every unit and parse it into JSON if (enviroPath) { diff --git a/src/extension.ts b/src/extension.ts index fa25450a..99a2ba60 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -79,6 +79,7 @@ import { forceLowerCaseDriveLetter, decodeVar, getFullEnvReport, + resolveVcpPaths, } from "./utilities"; import { @@ -1222,16 +1223,17 @@ function configureExtension(context: vscode.ExtensionContext) { ? activeEditor.document.uri.fsPath : fileFromUri; let enviroPath = getEnvPathForFilePath(filePath); - let fileName = path.parse(filePath).name; + let unitName = path.parse(filePath).name; - if (enviroPath?.endsWith(".vcp")) { - fileName = fileName + path.extname(filePath); - const parsed = path.parse(enviroPath); - enviroPath = path.join(parsed.dir, parsed.name); - } + // If the file is in a cover project, we need adapt the paths + ({ enviroPath, unitName } = resolveVcpPaths( + enviroPath, + unitName, + filePath + )); if (enviroPath) { - viewMCDCReport(enviroPath, fileName, args.lineNumber); + viewMCDCReport(enviroPath, unitName, args.lineNumber); } else { vscode.window.showErrorMessage( `Did not find environment name ${enviroPath} or path for file: ${filePath}` diff --git a/src/utilities.ts b/src/utilities.ts index 2eca5593..aa825fbc 100644 --- a/src/utilities.ts +++ b/src/utilities.ts @@ -459,3 +459,25 @@ export async function getFullEnvReport( // Return the generated HTML file path return htmlReportPath; } + +/** + * Checks if the environment is a Cover Project (.vcp). + * If so, it adjusts the environment path (removing .vcp) and appends the + * file extension to the unit name, as required by the Cover API. + */ +export function resolveVcpPaths( + enviroPath: string | null, + unitName: string, + fullFilePath: string +): { enviroPath: string | null; unitName: string } { + if (enviroPath?.endsWith(".vcp")) { + // Cover projects require the full filename (e.g. "manager.c" instead of "manager") + unitName = unitName + path.extname(fullFilePath); + + // The build directory for VCP is the path without the .vcp extension + const parsed = path.parse(enviroPath); + enviroPath = path.join(parsed.dir, parsed.name); + } + + return { enviroPath, unitName }; +} From a6065e5bb9afff331c97ca7e96dc5444c5809101 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Thu, 11 Dec 2025 17:12:12 +0100 Subject: [PATCH 07/26] Removed all buttons from vcp nodes --- package.json | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 6e16d53c..d5e2244c 100644 --- a/package.json +++ b/package.json @@ -967,97 +967,97 @@ { "command": "vectorcastTestExplorer.updateProjectEnvironment", "group": "vcast.project", - "when": "(testId =~ /^vcast:.*$/ && (testId in vectorcastTestExplorer.vcastUnbuiltEnviroList || testId in vectorcastTestExplorer.vcastEnviroList) && vectorcastTestExplorer.globalProjectIsOpenedChecker) && !config.vectorcastTestExplorer.automaticallyUpdateManageProject" + "when": "(testId =~ /^vcast:.*$/ && (testId in vectorcastTestExplorer.vcastUnbuiltEnviroList || testId in vectorcastTestExplorer.vcastEnviroList) && vectorcastTestExplorer.globalProjectIsOpenedChecker) && !config.vectorcastTestExplorer.automaticallyUpdateManageProject && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.buildProjectEnviro", "group": "vcast.build", - "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastUnbuiltEnviroList" + "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastUnbuiltEnviroList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.getEnvFullReport", "group": "vcast.build", - "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList" + "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.buildExecuteIncremental", "group": "vcast.build", - "when": "vectorcastTestExplorer.globalProjectIsOpenedChecker && ( testId =~ /\\.vcm$/ || testId in vectorcastTestExplorer.globalProjectCompilers || testId in vectorcastTestExplorer.globalProjectTestsuites || (testId =~ /^vcast:.*$/ && ( testId in vectorcastTestExplorer.vcastEnviroList || testId in vectorcastTestExplorer.vcastUnbuiltEnviroList)))" + "when": "vectorcastTestExplorer.globalProjectIsOpenedChecker && ( testId =~ /\\.vcm$/ || testId in vectorcastTestExplorer.globalProjectCompilers || testId in vectorcastTestExplorer.globalProjectTestsuites || (testId =~ /^vcast:.*$/ && ( testId in vectorcastTestExplorer.vcastEnviroList || testId in vectorcastTestExplorer.vcastUnbuiltEnviroList))) && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.rebuildEnviro", "group": "vcast.build", - "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList" + "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.cleanEnviro", "group": "vcast.build", - "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && vectorcastTestExplorer.globalProjectIsOpenedChecker && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList" + "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && vectorcastTestExplorer.globalProjectIsOpenedChecker && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.openVCAST", "group": "vcast.enviroManagement", - "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList" + "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.deleteEnviro", "group": "vcast.enviroManagement", - "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && !vectorcastTestExplorer.globalProjectIsOpenedChecker" + "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && !vectorcastTestExplorer.globalProjectIsOpenedChecker && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.deleteEnviroFromProject", "group": "vcast.enviroManagement", - "when": "testId =~ /^vcast:.*$/ && (testId in vectorcastTestExplorer.vcastUnbuiltEnviroList || testId in vectorcastTestExplorer.vcastEnviroList) && vectorcastTestExplorer.globalProjectIsOpenedChecker" + "when": "testId =~ /^vcast:.*$/ && (testId in vectorcastTestExplorer.vcastUnbuiltEnviroList || testId in vectorcastTestExplorer.vcastEnviroList) && vectorcastTestExplorer.globalProjectIsOpenedChecker && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.removeTestsuite", "group": "vcast.enviroManagement", - "when": "testId =~ /^vcast:.*$/ && (testId in vectorcastTestExplorer.vcastUnbuiltEnviroList || testId in vectorcastTestExplorer.vcastEnviroList) && vectorcastTestExplorer.globalProjectIsOpenedChecker" + "when": "testId =~ /^vcast:.*$/ && (testId in vectorcastTestExplorer.vcastUnbuiltEnviroList || testId in vectorcastTestExplorer.vcastEnviroList) && vectorcastTestExplorer.globalProjectIsOpenedChecker && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.editTestScript", "group": "vcast.testScript", - "when": "testId =~ /^vcast:.*$/ && !(testId =~ /.*coded_tests_driver.*/) && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList" + "when": "testId =~ /^vcast:.*$/ && !(testId =~ /.*coded_tests_driver.*/) && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.createTestScript", "group": "vcast.testScript", - "when": "testId =~ /^vcast:.*$/ && testId not in vectorcastTestExplorer.vcastEnviroList && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && !(testId =~ /.*coded_tests_driver.*/ )" + "when": "testId =~ /^vcast:.*$/ && testId not in vectorcastTestExplorer.vcastEnviroList && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && !(testId =~ /.*coded_tests_driver.*/ ) && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.editCodedTest", "group": "vcast.testScript", - "when": "testId =~ /^vcast:.*$/ && testId not in vectorcastTestExplorer.vcastEnviroList && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && testId =~ /.*coded_tests_driver.+/" + "when": "testId =~ /^vcast:.*$/ && testId not in vectorcastTestExplorer.vcastEnviroList && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && testId =~ /.*coded_tests_driver.+/ && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.addCodedTests", "group": "vcast.testScript", - "when": "testId =~ /^vcast:.*$/ && testId =~ /.*coded_tests_driver$/ && testId not in vectorcastTestExplorer.vcastHasCodedTestsList" + "when": "testId =~ /^vcast:.*$/ && testId =~ /.*coded_tests_driver$/ && testId not in vectorcastTestExplorer.vcastHasCodedTestsList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.generateCodedTests", "group": "vcast.testScript", - "when": "testId =~ /^vcast:.*$/ && testId =~ /.*coded_tests_driver$/ && testId not in vectorcastTestExplorer.vcastHasCodedTestsList" + "when": "testId =~ /^vcast:.*$/ && testId =~ /.*coded_tests_driver$/ && testId not in vectorcastTestExplorer.vcastHasCodedTestsList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.removeCodedTests", "group": "vcast.testScript", - "when": "testId =~ /^vcast:.*$/ && testId =~ /.*coded_tests_driver$/ && testId in vectorcastTestExplorer.vcastHasCodedTestsList" + "when": "testId =~ /^vcast:.*$/ && testId =~ /.*coded_tests_driver$/ && testId in vectorcastTestExplorer.vcastHasCodedTestsList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.insertBasisPathTests", "group": "vcast.testGeneration", - "when": "testId =~ /^vcast:.*$/ && !(testId =~ /^.*<>.*$/) && !(testId =~ /^.*<>.*$/) && !(testId =~ /.*coded_tests_driver.*/) && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList" + "when": "testId =~ /^vcast:.*$/ && !(testId =~ /^.*<>.*$/) && !(testId =~ /^.*<>.*$/) && !(testId =~ /.*coded_tests_driver.*/) && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.insertATGTests", "group": "vcast.testGeneration", - "when": "testId =~ /^vcast:.*$/ && vectorcastTestExplorer.atgAvailable && !(testId =~ /^.*<>.*$/) && !(testId =~ /^.*<>.*$/) && !(testId =~ /.*coded_tests_driver.*/) && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList" + "when": "testId =~ /^vcast:.*$/ && vectorcastTestExplorer.atgAvailable && !(testId =~ /^.*<>.*$/) && !(testId =~ /^.*<>.*$/) && !(testId =~ /.*coded_tests_driver.*/) && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.deleteTest", "group": "vcast.delete", - "when": "testId =~ /^vcast:.*$/ && !(testId =~ /.*coded_tests_driver.*/) && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList" + "when": "testId =~ /^vcast:.*$/ && !(testId =~ /.*coded_tests_driver.*/) && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.deleteTestsuite", @@ -1072,37 +1072,37 @@ { "command": "vectorcastTestExplorer.importRequirementsFromGateway", "group": "vcast@8", - "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && vectorcastTestExplorer.reqs2xFeatureEnabled && testId not in vectorcastTestExplorer.vcastRequirementsAvailable && vectorcastTestExplorer.generateRequirementsEnabled" + "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && vectorcastTestExplorer.reqs2xFeatureEnabled && testId not in vectorcastTestExplorer.vcastRequirementsAvailable && vectorcastTestExplorer.generateRequirementsEnabled && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.generateRequirements", "group": "vcast@8", - "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && vectorcastTestExplorer.reqs2xFeatureEnabled && testId not in vectorcastTestExplorer.vcastRequirementsAvailable && vectorcastTestExplorer.generateRequirementsEnabled" + "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && vectorcastTestExplorer.reqs2xFeatureEnabled && testId not in vectorcastTestExplorer.vcastRequirementsAvailable && vectorcastTestExplorer.generateRequirementsEnabled && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.showRequirements", "group": "vcast@9", - "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && vectorcastTestExplorer.reqs2xFeatureEnabled && testId in vectorcastTestExplorer.vcastRequirementsAvailable && vectorcastTestExplorer.generateRequirementsEnabled" + "when": "testId =~ /^vcast:.*$/ && testId in vectorcastTestExplorer.vcastEnviroList && vectorcastTestExplorer.reqs2xFeatureEnabled && testId in vectorcastTestExplorer.vcastRequirementsAvailable && vectorcastTestExplorer.generateRequirementsEnabled && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.generateTestsFromRequirements", "group": "vcast@10", - "when": "testId =~ /^vcast:.*$/ && vectorcastTestExplorer.reqs2xFeatureEnabled" + "when": "testId =~ /^vcast:.*$/ && vectorcastTestExplorer.reqs2xFeatureEnabled && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.removeRequirements", "group": "vcast@9", - "when": "testId =~ /^vcast:.*$/ && vectorcastTestExplorer.reqs2xFeatureEnabled && testId in vectorcastTestExplorer.vcastRequirementsAvailable && vectorcastTestExplorer.generateRequirementsEnabled" + "when": "testId =~ /^vcast:.*$/ && vectorcastTestExplorer.reqs2xFeatureEnabled && testId in vectorcastTestExplorer.vcastRequirementsAvailable && vectorcastTestExplorer.generateRequirementsEnabled && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.populateRequirementsGateway", "group": "vcast@9", - "when": "testId =~ /^vcast:.*$/ && vectorcastTestExplorer.reqs2xFeatureEnabled && testId in vectorcastTestExplorer.vcastRequirementsAvailable && vectorcastTestExplorer.generateRequirementsEnabled" + "when": "testId =~ /^vcast:.*$/ && vectorcastTestExplorer.reqs2xFeatureEnabled && testId in vectorcastTestExplorer.vcastRequirementsAvailable && vectorcastTestExplorer.generateRequirementsEnabled && !(testId =~ /\\.vcp$/)" }, { "command": "vectorcastTestExplorer.viewResults", "group": "vcast.results", - "when": "testId =~ /^vcast:.*$/ && testId not in vectorcastTestExplorer.vcastEnviroList && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList" + "when": "testId =~ /^vcast:.*$/ && testId not in vectorcastTestExplorer.vcastEnviroList && testId not in vectorcastTestExplorer.vcastUnbuiltEnviroList && !(testId =~ /\\.vcp$/)" } ] }, From f66035d560f1f28ef6852bb021fc1efaeb226dd8 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Thu, 18 Dec 2025 14:46:05 +0100 Subject: [PATCH 08/26] C Coverage Tests --- package.json | 3 +- src/editorDecorator.ts | 3 +- .../e2e/test/cCoverage/c_cov_example.sh | 55 ++++++ .../e2e/test/specs/vcast_c_tests.test.ts | 186 ++++++++++++++++++ tests/internal/e2e/test/specs_config.ts | 8 + tests/internal/e2e/test/wdio.conf.ts | 26 +++ 6 files changed, 278 insertions(+), 3 deletions(-) create mode 100644 tests/internal/e2e/test/cCoverage/c_cov_example.sh create mode 100644 tests/internal/e2e/test/specs/vcast_c_tests.test.ts diff --git a/package.json b/package.json index d5e2244c..e511b868 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,7 @@ "activationEvents": [ "workspaceContains:**/UNITDATA.VCD", "workspaceContains:**/*.vcm", - "workspaceContains:**/*.vcp", - "workspaceContains:**/*.env" + "workspaceContains:**/*.vcp" ], "contributes": { "viewsWelcome": [ diff --git a/src/editorDecorator.ts b/src/editorDecorator.ts index 275e18bb..679bf24b 100644 --- a/src/editorDecorator.ts +++ b/src/editorDecorator.ts @@ -6,6 +6,7 @@ import { testNodeType } from "./testData"; import { getEnvPathForFilePath, getRangeOption, + normalizePath, resolveVcpPaths, } from "./utilities"; @@ -36,7 +37,7 @@ export async function updateCurrentActiveUnitMCDCLines() { let activeEditor = vscode.window.activeTextEditor; if (activeEditor) { // First we need to get the env name from the active file - const filePath = activeEditor.document.uri.fsPath; + const filePath = normalizePath(activeEditor.document.uri.fsPath); let enviroPath = getEnvPathForFilePath(filePath); // Get the unit name based on the file name without extension diff --git a/tests/internal/e2e/test/cCoverage/c_cov_example.sh b/tests/internal/e2e/test/cCoverage/c_cov_example.sh new file mode 100644 index 00000000..b51cd3d0 --- /dev/null +++ b/tests/internal/e2e/test/cCoverage/c_cov_example.sh @@ -0,0 +1,55 @@ +#!/bin/sh -ex + +# Always start with a clean working directory +rm -fr work +mkdir work +cd work +export WORK_DIRECTORY=$PWD +# export VECTORCAST_DIR=/home/JOBDATA/VectorCAST/vc20__86806_vcwrap__87490_inst_mod/deliver/linux64/debug + +# Download lua 5.3.5 for instrumentation +time wget https://www.lua.org/ftp/lua-5.4.0.tar.gz +time tar -zxvf lua-5.4.0.tar.gz + + +# Configuration VectorCAST, including the compiler +$VECTORCAST_DIR/clicast template GNU_CPP11_X +$VECTORCAST_DIR/clicast option VCAST_COVERAGE_FOR_HEADERS TRUE +$VECTORCAST_DIR/clicast option VCAST_COVERAGE_FOR_AGGREGATE_INIT TRUE + + +# Create the cover environment +time $VECTORCAST_DIR/clicast cover environment script_run ../env.enc + + +$VECTORCAST_DIR/clicast -e env cover env disable_instrumentation + + +# These commands will be put into a single clicast build command + + # Single step instrument and build + cd lua-5.4.0/src + + # The command that instruments and builds + time make generic -j16 -B + + # Add the instrumentation data into the cover environment + cd $WORK_DIRECTORY + +# Run the tests +mkdir lua_tests +cd lua_tests +time wget https://www.lua.org/tests/lua-5.4.0-tests.tar.gz +time tar -zxvf lua-5.4.0-tests.tar.gz +cd lua-5.4.0-tests +set +e +../../lua-5.4.0/src/lua all.lua +mv TESTINSS.DAT TESTINSS.DAT.all.lua +../../lua-5.4.0/src/lua api.lua +mv TESTINSS.DAT TESTINSS.DAT.api.lua +set -e + +# Add the test suite result to the cover environment +cd $WORK_DIRECTORY +time $VECTORCAST_DIR/clicast -e env cover result add lua_tests/lua-5.4.0-tests/TESTINSS.DAT.all.lua all.lua +time $VECTORCAST_DIR/clicast -e env cover result add lua_tests/lua-5.4.0-tests/TESTINSS.DAT.api.lua api.lua \ No newline at end of file diff --git a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts new file mode 100644 index 00000000..22df4eac --- /dev/null +++ b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts @@ -0,0 +1,186 @@ +// Test/specs/vcast.test.ts +import { + TextEditor, + type BottomBarPanel, + type Workbench, +} from "wdio-vscode-service"; +import { Key } from "webdriverio"; +import { + releaseCtrl, + executeCtrlClickOn, + expandWorkspaceFolderSectionInExplorer, + updateTestID, + checkIfRequestInLogs, + checkElementExistsInHTML, +} from "../test_utils/vcast_utils"; +import { TIMEOUT } from "../test_utils/vcast_utils"; +import { checkForServerRunnability } from "../../../../unit/getToolversion"; + +describe("vTypeCheck VS Code Extension", () => { + let bottomBar: BottomBarPanel; + let workbench: Workbench; + let useDataServer: boolean = true; + before(async () => { + workbench = await browser.getWorkbench(); + // Opening bottom bar and problems view before running any tests + bottomBar = workbench.getBottomBar(); + await bottomBar.toggle(true); + process.env.E2E_TEST_ID = "0"; + let releaseIsSuitableForServer = await checkForServerRunnability(); + if (process.env.VCAST_USE_PYTHON || !releaseIsSuitableForServer) { + useDataServer = false; + } + }); + + it("test 1: should be able to load VS Code", async () => { + await updateTestID(); + expect(await workbench.getTitleBar().getTitle()).toBe( + "[Extension Development Host] vcastTutorial - Visual Studio Code" + ); + }); + + it("should activate vcastAdapter", async () => { + await updateTestID(); + + await browser.keys([Key.Control, Key.Shift, "p"]); + // Typing Vector in the quick input box + // This brings up VectorCAST Test Explorer: Configure + // so just need to hit Enter to activate + for (const character of "vector") { + await browser.keys(character); + } + + await browser.keys(Key.Enter); + + const activityBar = workbench.getActivityBar(); + const viewControls = await activityBar.getViewControls(); + for (const viewControl of viewControls) { + console.log(await viewControl.getTitle()); + } + + await bottomBar.toggle(true); + const outputView = await bottomBar.openOutputView(); + + console.log("Waiting for VectorCAST activation"); + await $("aria/VectorCAST Test Pane Initialization"); + console.log("WAITING FOR TESTING"); + await browser.waitUntil( + async () => (await activityBar.getViewControl("Testing")) !== undefined, + { timeout: TIMEOUT } + ); + console.log("WAITING FOR TEST EXPLORER"); + browser.pause(10000); + await browser.waitUntil(async () => + (await outputView.getChannelNames()) + .toString() + .includes("VectorCAST Test Explorer") + ); + await outputView.selectChannel("VectorCAST Test Explorer"); + console.log("Channel selected"); + console.log("WAITING FOR LANGUAGE SERVER"); + await browser.waitUntil( + async () => + (await outputView.getText()) + .toString() + .includes("Starting the language server"), + { timeout: TIMEOUT } + ); + + const testingView = await activityBar.getViewControl("Testing"); + await testingView?.openView(); + }); + + it("should check for server starting logs if in server mode", async () => { + const outputView = await bottomBar.openOutputView(); + + // Check if server started + if (useDataServer) { + // Check message pane for expected message + await browser.waitUntil( + async () => + (await outputView.getText()) + .toString() + .includes("Started VectorCAST Data Server"), + { timeout: TIMEOUT } + ); + + // Check server logs + const logs = await checkIfRequestInLogs(3, ["port:", "clicast"]); + expect(logs).toBe(true); + } + }); + + it("should check for c coverage", async () => { + workbench = await browser.getWorkbench(); + bottomBar = workbench.getBottomBar(); + const outputView = await bottomBar.openOutputView(); + const workspaceFolderSection = + await expandWorkspaceFolderSectionInExplorer("vcastTutorial"); + const workFolder = workspaceFolderSection.findItem("work"); + await (await workFolder).select(); + const luaFolder = workspaceFolderSection.findItem("lua-5.4.0"); + await (await luaFolder).select(); + const srcFolder = workspaceFolderSection.findItem("src"); + await (await srcFolder).select(); + const file = workspaceFolderSection.findItem("lua.c"); + await (await file).select(); + + // Check if the file is already open in the editor + const editorView = workbench.getEditorView(); + // List of open editor titles + const openEditors = await editorView.getOpenEditorTitles(); + const isFileOpen = openEditors.includes("lua.c"); + if (!isFileOpen) { + // Select file from the explorer if not already open + await (await file).select(); + } + const icon = "no-cover-icon-with-mcdc"; + const tab = (await editorView.openEditor("lua.c")) as TextEditor; + const lineNumberElement = await $(`.line-numbers=80`); + const flaskElement = await ( + await lineNumberElement.parentElement() + ).$(".cgmr.codicon"); + const backgroundImageCSS = + await flaskElement.getCSSProperty("background-image"); + const backgroundImageURL = backgroundImageCSS.value; + const BEAKER = `/${icon}`; + expect(backgroundImageURL.includes(BEAKER)).toBe(true); + + await flaskElement.click({ button: 2 }); + await (await $("aria/VectorCAST MC/DC Report")).click(); + await browser.waitUntil( + async () => + (await outputView.getText()) + .toString() + .includes("Report file path is:"), + { timeout: TIMEOUT } + ); + await browser.waitUntil( + async () => (await workbench.getAllWebviews()).length > 0, + { timeout: TIMEOUT } + ); + const webviews = await workbench.getAllWebviews(); + expect(webviews).toHaveLength(1); + const webview = webviews[0]; + + await webview.open(); + + // Retrieve the HTML and count the number of div.report-block + const reportBlockCount = await browser.execute(() => { + // Use querySelectorAll to count how many
elements are in the document + return document.querySelectorAll("div.report-block").length; + }); + + expect(reportBlockCount).toEqual(1); + + // Some important lines we want to check for in the report + await expect(await checkElementExistsInHTML("lua.c")).toBe(true); + await expect(await checkElementExistsInHTML("80")).toBe(true); + await expect( + await checkElementExistsInHTML("Pairs satisfied: 0 of 1 ( 0% )") + ).toBe(true); + + await webview.close(); + await editorView.closeEditor("VectorCAST Report", 1); + }); +}); diff --git a/tests/internal/e2e/test/specs_config.ts b/tests/internal/e2e/test/specs_config.ts index 251b82e4..f5f95449 100755 --- a/tests/internal/e2e/test/specs_config.ts +++ b/tests/internal/e2e/test/specs_config.ts @@ -170,6 +170,14 @@ export function getSpecGroups(useVcast24: boolean) { }, params: {}, }; + specGroups["c_coverage"] = { + specs: ["./**/**/vcast_c_tests.test.ts"], + env: { + VCAST_USE_PYTHON: "True", + C_COVERAGE: "True", + }, + params: {}, + }; specGroups["basic_user_interactions_server"] = { specs: [ diff --git a/tests/internal/e2e/test/wdio.conf.ts b/tests/internal/e2e/test/wdio.conf.ts index 18af6977..92add166 100644 --- a/tests/internal/e2e/test/wdio.conf.ts +++ b/tests/internal/e2e/test/wdio.conf.ts @@ -335,6 +335,7 @@ export const config: Options.Testrunner = { async () => await buildEnvsWithSpecificReleases(initialWorkdir), ], ["MANAGE_TEST", async () => await testManage(initialWorkdir)], + ["C_COVERAGE", async () => await testCCoverage(initialWorkdir)], ]); // Determine the environment key @@ -392,6 +393,31 @@ export const config: Options.Testrunner = { * ================================================================================================ */ + async function testCCoverage(initialWorkdir: string) { + const testInputCCoverage = path.join(initialWorkdir, "test", "cCoverage"); + const workFolder = path.join(testInputCCoverage, "work"); + + await checkVPython(); + clicastExecutablePath = await checkClicast(); + process.env.CLICAST_PATH = clicastExecutablePath; + + // Execute the coverage build script + const build_coverage = `cd ${testInputCCoverage} && bash ./c_cov_example.sh`; + await executeCommand(build_coverage); + + await prepareConfig(initialWorkdir, clicastExecutablePath); + + // Copy the work folder contents to vcastTutorial + const destFolder = path.join(initialWorkdir, "test", "vcastTutorial"); + if (process.platform === "win32") { + await executeCommand( + `xcopy /s /i /y ${workFolder} ${destFolder} > NUL 2> NUL` + ); + } else { + await executeCommand(`cp -r ${workFolder}/* ${destFolder}/`); + } + } + async function testManage(initialWorkdir: string) { const testInputManage = path.join(initialWorkdir, "test", "manage"); const build_demo = `cd ${testInputManage} && ./demo_build.sh`; From f41f026191d29d409dc449107f5ca24268a06da2 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Thu, 18 Dec 2025 14:58:35 +0100 Subject: [PATCH 09/26] c cov test correction --- tests/internal/e2e/test/specs/vcast_c_tests.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts index 22df4eac..dfa05251 100644 --- a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts +++ b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts @@ -116,8 +116,6 @@ describe("vTypeCheck VS Code Extension", () => { const outputView = await bottomBar.openOutputView(); const workspaceFolderSection = await expandWorkspaceFolderSectionInExplorer("vcastTutorial"); - const workFolder = workspaceFolderSection.findItem("work"); - await (await workFolder).select(); const luaFolder = workspaceFolderSection.findItem("lua-5.4.0"); await (await luaFolder).select(); const srcFolder = workspaceFolderSection.findItem("src"); From a684c8d1b57e26842e4596b6bce999fffbc5ceea Mon Sep 17 00:00:00 2001 From: Den1552 Date: Thu, 18 Dec 2025 15:23:01 +0100 Subject: [PATCH 10/26] c cov test correction 2 --- .../e2e/test/specs/vcast_c_tests.test.ts | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts index dfa05251..aac29954 100644 --- a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts +++ b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts @@ -12,6 +12,7 @@ import { updateTestID, checkIfRequestInLogs, checkElementExistsInHTML, + findTreeNodeAtLevel, } from "../test_utils/vcast_utils"; import { TIMEOUT } from "../test_utils/vcast_utils"; import { checkForServerRunnability } from "../../../../unit/getToolversion"; @@ -110,9 +111,21 @@ describe("vTypeCheck VS Code Extension", () => { } }); + it("should check for vcp node", async () => { + const outputView = await bottomBar.openOutputView(); + const activityBar = workbench.getActivityBar(); + const testingView = await activityBar.getViewControl("Testing"); + await testingView?.openView(); + const vcpNode = await findTreeNodeAtLevel(0, "env.vcp"); + expect(compilerNode).toBeDefined(); + }); + it("should check for c coverage", async () => { workbench = await browser.getWorkbench(); bottomBar = workbench.getBottomBar(); + const activityBar = workbench.getActivityBar(); + const testingView = await activityBar.getViewControl("Explorer"); + await testingView?.openView(); const outputView = await bottomBar.openOutputView(); const workspaceFolderSection = await expandWorkspaceFolderSectionInExplorer("vcastTutorial"); @@ -134,7 +147,9 @@ describe("vTypeCheck VS Code Extension", () => { } const icon = "no-cover-icon-with-mcdc"; const tab = (await editorView.openEditor("lua.c")) as TextEditor; - const lineNumberElement = await $(`.line-numbers=80`); + + const lineNumber = 65; + const lineNumberElement = await $(`.line-numbers=${lineNumber}`); const flaskElement = await ( await lineNumberElement.parentElement() ).$(".cgmr.codicon"); @@ -173,9 +188,9 @@ describe("vTypeCheck VS Code Extension", () => { // Some important lines we want to check for in the report await expect(await checkElementExistsInHTML("lua.c")).toBe(true); - await expect(await checkElementExistsInHTML("80")).toBe(true); + await expect(await checkElementExistsInHTML("65")).toBe(true); await expect( - await checkElementExistsInHTML("Pairs satisfied: 0 of 1 ( 0% )") + await checkElementExistsInHTML("Pairs satisfied: 0 of 2 ( 0% )") ).toBe(true); await webview.close(); From 569e73df99882f7f38df68e974a2608bbe331148 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Thu, 18 Dec 2025 16:47:20 +0100 Subject: [PATCH 11/26] Added enc file --- tests/internal/e2e/test/cCoverage/env.enc | 41 +++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/internal/e2e/test/cCoverage/env.enc diff --git a/tests/internal/e2e/test/cCoverage/env.enc b/tests/internal/e2e/test/cCoverage/env.enc new file mode 100644 index 00000000..818093db --- /dev/null +++ b/tests/internal/e2e/test/cCoverage/env.enc @@ -0,0 +1,41 @@ + + + 2 + + env + STATEMENT_MCDC + + + SourceRoot + ./lua-5.4.0 + src + + + PROBE_ID: 2 + PROBE_UNIT: luac.c + PROBE_FUNCTION: main + PROBE_LINE: return 0; + PROBE_CONTEXT_BEFORE: + if (lua_pcallk(L, (2), (0), (0), 0, ((void *)0))!=0) fatal(lua_tolstring(L, (-1), ((void *)0))); + lua_close(L); + END_PROBE_CONTEXT_BEFORE: + PROBE_CODE: + VCAST_DUMP_COVERAGE_DATA(); + END_PROBE_CODE: + + + + SourceRoot + src/lua.c + + true + + + + SourceRoot + src/luac.c + + true + + + From 5fa514c5adb31b8863fdf8b5b47cc6526addb2a0 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Thu, 18 Dec 2025 16:58:14 +0100 Subject: [PATCH 12/26] var name change --- tests/internal/e2e/test/specs/vcast_c_tests.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts index aac29954..811db69e 100644 --- a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts +++ b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts @@ -117,7 +117,7 @@ describe("vTypeCheck VS Code Extension", () => { const testingView = await activityBar.getViewControl("Testing"); await testingView?.openView(); const vcpNode = await findTreeNodeAtLevel(0, "env.vcp"); - expect(compilerNode).toBeDefined(); + expect(vcpNode).toBeDefined(); }); it("should check for c coverage", async () => { From 5f7238db9bae4d94cf23c623f1ecbcc17913d583 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Fri, 19 Dec 2025 09:04:32 +0100 Subject: [PATCH 13/26] Adapted tests --- tests/internal/e2e/test/specs/vcast_c_tests.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts index 811db69e..c5f59bd0 100644 --- a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts +++ b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts @@ -149,6 +149,7 @@ describe("vTypeCheck VS Code Extension", () => { const tab = (await editorView.openEditor("lua.c")) as TextEditor; const lineNumber = 65; + await tab.moveCursor(lineNumber, 1); const lineNumberElement = await $(`.line-numbers=${lineNumber}`); const flaskElement = await ( await lineNumberElement.parentElement() From 6ad76d0fb49d1612b87f30c055b421e65b5cf6d3 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Fri, 19 Dec 2025 14:13:19 +0100 Subject: [PATCH 14/26] Trying to add pause after file selection --- .../internal/e2e/test/specs/vcast_c_tests.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts index c5f59bd0..23f8f2b1 100644 --- a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts +++ b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts @@ -111,6 +111,17 @@ describe("vTypeCheck VS Code Extension", () => { } }); + it("should change coverageKind and Rebuild env", async () => { + // We need to change the covarage kind to Statement+MCDC in order to get the MCDC lines + let settingsEditor = await workbench.openSettings(); + const coverageKindSetting = await settingsEditor.findSetting( + "Coverage Kind", + "Vectorcast Test Explorer", + "Build" + ); + await coverageKindSetting.setValue("Statement+MCDC"); + }); + it("should check for vcp node", async () => { const outputView = await bottomBar.openOutputView(); const activityBar = workbench.getActivityBar(); @@ -145,6 +156,9 @@ describe("vTypeCheck VS Code Extension", () => { // Select file from the explorer if not already open await (await file).select(); } + + await browser.pause(30000); + const icon = "no-cover-icon-with-mcdc"; const tab = (await editorView.openEditor("lua.c")) as TextEditor; From 035849500b51510b511bbe4f5550511f490769ea Mon Sep 17 00:00:00 2001 From: Den1552 Date: Fri, 19 Dec 2025 14:22:21 +0100 Subject: [PATCH 15/26] Removed setting change --- tests/internal/e2e/test/specs/vcast_c_tests.test.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts index 23f8f2b1..79be543d 100644 --- a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts +++ b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts @@ -111,17 +111,6 @@ describe("vTypeCheck VS Code Extension", () => { } }); - it("should change coverageKind and Rebuild env", async () => { - // We need to change the covarage kind to Statement+MCDC in order to get the MCDC lines - let settingsEditor = await workbench.openSettings(); - const coverageKindSetting = await settingsEditor.findSetting( - "Coverage Kind", - "Vectorcast Test Explorer", - "Build" - ); - await coverageKindSetting.setValue("Statement+MCDC"); - }); - it("should check for vcp node", async () => { const outputView = await bottomBar.openOutputView(); const activityBar = workbench.getActivityBar(); From 1102efb66f7a811e46daa9c5bbe569065a3773f2 Mon Sep 17 00:00:00 2001 From: Den1552 Date: Fri, 19 Dec 2025 14:47:11 +0100 Subject: [PATCH 16/26] Added debug log --- src/editorDecorator.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/editorDecorator.ts b/src/editorDecorator.ts index 679bf24b..155c1406 100644 --- a/src/editorDecorator.ts +++ b/src/editorDecorator.ts @@ -66,6 +66,8 @@ export async function updateCurrentActiveUnitMCDCLines() { const mcdcLinesForUnit = mcdcUnitCoverageLines[unitName]; // Check if there are no MCDC lines for the unit --> for example when the env is build with only Statement coverage // and the user changes it to Statement+MCDC in the settings + vectorMessage(`MCDC LINES FOR UNIT: ${unitName}`); + vectorMessage(mcdcLinesForUnit.toString()); if (mcdcLinesForUnit) { currentActiveUnitMCDCLines = mcdcUnitCoverageLines[unitName]; } else { From 3763f9824e2d7a1b5230eba90dac838c05de8e50 Mon Sep 17 00:00:00 2001 From: Denis Moslavac Date: Tue, 13 Jan 2026 09:11:46 +0100 Subject: [PATCH 17/26] Adapted c tests --- .../e2e/test/specs/vcast_c_tests.test.ts | 49 ++++++++++++++----- tests/internal/e2e/test/wdio.conf.ts | 31 +++++++----- 2 files changed, 56 insertions(+), 24 deletions(-) diff --git a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts index 79be543d..1ccb090c 100644 --- a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts +++ b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts @@ -126,45 +126,65 @@ describe("vTypeCheck VS Code Extension", () => { const activityBar = workbench.getActivityBar(); const testingView = await activityBar.getViewControl("Explorer"); await testingView?.openView(); - const outputView = await bottomBar.openOutputView(); + + await bottomBar.toggle(false); + const workspaceFolderSection = await expandWorkspaceFolderSectionInExplorer("vcastTutorial"); + + const workFolder = workspaceFolderSection.findItem("work"); + await (await workFolder).select(); + const luaFolder = workspaceFolderSection.findItem("lua-5.4.0"); await (await luaFolder).select(); + const srcFolder = workspaceFolderSection.findItem("src"); await (await srcFolder).select(); + const file = workspaceFolderSection.findItem("lua.c"); await (await file).select(); // Check if the file is already open in the editor const editorView = workbench.getEditorView(); - // List of open editor titles const openEditors = await editorView.getOpenEditorTitles(); const isFileOpen = openEditors.includes("lua.c"); + if (!isFileOpen) { - // Select file from the explorer if not already open await (await file).select(); } - await browser.pause(30000); + // Give VS Code some time to settle (language server, decorations, etc.) + await browser.pause(30_000); const icon = "no-cover-icon-with-mcdc"; - const tab = (await editorView.openEditor("lua.c")) as TextEditor; - const lineNumber = 65; + + const tab = (await editorView.openEditor("lua.c")) as TextEditor; await tab.moveCursor(lineNumber, 1); + + // Use the EXACT same pattern as the working test const lineNumberElement = await $(`.line-numbers=${lineNumber}`); const flaskElement = await ( await lineNumberElement.parentElement() ).$(".cgmr.codicon"); + + // Verify the icon const backgroundImageCSS = await flaskElement.getCSSProperty("background-image"); - const backgroundImageURL = backgroundImageCSS.value; - const BEAKER = `/${icon}`; - expect(backgroundImageURL.includes(BEAKER)).toBe(true); + expect(backgroundImageCSS.value.includes(`/${icon}`)).toBe(true); + // Close bottom bar before context menu + await bottomBar.toggle(false); + await browser.pause(1000); + + // Open context menu await flaskElement.click({ button: 2 }); + await browser.pause(2000); await (await $("aria/VectorCAST MC/DC Report")).click(); + + const outputView = await bottomBar.openOutputView(); + + // Wait for report generation await browser.waitUntil( async () => (await outputView.getText()) @@ -172,31 +192,34 @@ describe("vTypeCheck VS Code Extension", () => { .includes("Report file path is:"), { timeout: TIMEOUT } ); + + // Wait for webview to open await browser.waitUntil( async () => (await workbench.getAllWebviews()).length > 0, { timeout: TIMEOUT } ); + const webviews = await workbench.getAllWebviews(); expect(webviews).toHaveLength(1); - const webview = webviews[0]; + const webview = webviews[0]; await webview.open(); - // Retrieve the HTML and count the number of div.report-block + // Count report blocks in the HTML const reportBlockCount = await browser.execute(() => { - // Use querySelectorAll to count how many
elements are in the document return document.querySelectorAll("div.report-block").length; }); expect(reportBlockCount).toEqual(1); - // Some important lines we want to check for in the report + // Validate report content await expect(await checkElementExistsInHTML("lua.c")).toBe(true); await expect(await checkElementExistsInHTML("65")).toBe(true); await expect( await checkElementExistsInHTML("Pairs satisfied: 0 of 2 ( 0% )") ).toBe(true); + // Cleanup await webview.close(); await editorView.closeEditor("VectorCAST Report", 1); }); diff --git a/tests/internal/e2e/test/wdio.conf.ts b/tests/internal/e2e/test/wdio.conf.ts index 92add166..f82620b8 100644 --- a/tests/internal/e2e/test/wdio.conf.ts +++ b/tests/internal/e2e/test/wdio.conf.ts @@ -394,28 +394,37 @@ export const config: Options.Testrunner = { */ async function testCCoverage(initialWorkdir: string) { + const workFolder = path.join(initialWorkdir, "test", "vcastTutorial"); const testInputCCoverage = path.join(initialWorkdir, "test", "cCoverage"); - const workFolder = path.join(testInputCCoverage, "work"); await checkVPython(); clicastExecutablePath = await checkClicast(); process.env.CLICAST_PATH = clicastExecutablePath; - // Execute the coverage build script - const build_coverage = `cd ${testInputCCoverage} && bash ./c_cov_example.sh`; - await executeCommand(build_coverage); - await prepareConfig(initialWorkdir, clicastExecutablePath); - // Copy the work folder contents to vcastTutorial - const destFolder = path.join(initialWorkdir, "test", "vcastTutorial"); + // Create vcastTutorial directory + await mkdir(workFolder, { recursive: true }); + + // Copy the build script to vcastTutorial + const scriptSource = path.join(testInputCCoverage, "c_cov_example.sh"); + const scriptDest = path.join(workFolder, "c_cov_example.sh"); + const envSource = path.join(testInputCCoverage, "env.enc"); + const envDest = path.join(workFolder, "env.enc"); + if (process.platform === "win32") { - await executeCommand( - `xcopy /s /i /y ${workFolder} ${destFolder} > NUL 2> NUL` - ); + await executeCommand(`copy /y ${scriptSource} ${scriptDest}`); + await executeCommand(`copy /y ${envSource} ${envDest}`); } else { - await executeCommand(`cp -r ${workFolder}/* ${destFolder}/`); + await executeCommand(`cp ${scriptSource} ${scriptDest}`); + await executeCommand(`cp ${envSource} ${envDest}`); } + + // Execute the coverage build script in vcastTutorial + const build_coverage = `cd ${workFolder} && bash ./c_cov_example.sh`; + await executeCommand(build_coverage); + + // No copy needed - everything is already in the right place! } async function testManage(initialWorkdir: string) { From f1ba3fe30fc1ce2ce0fcdc63a6593f3120ace831 Mon Sep 17 00:00:00 2001 From: Denis Moslavac Date: Tue, 13 Jan 2026 13:41:20 +0100 Subject: [PATCH 18/26] added debugging logs --- src/editorDecorator.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/editorDecorator.ts b/src/editorDecorator.ts index 155c1406..212602c2 100644 --- a/src/editorDecorator.ts +++ b/src/editorDecorator.ts @@ -38,8 +38,9 @@ export async function updateCurrentActiveUnitMCDCLines() { if (activeEditor) { // First we need to get the env name from the active file const filePath = normalizePath(activeEditor.document.uri.fsPath); + vectorMessage(`filepath: ${filePath}`); let enviroPath = getEnvPathForFilePath(filePath); - + vectorMessage(`enviroPath: ${enviroPath}`); // Get the unit name based on the file name without extension const fullPath = activeEditor.document.fileName; let unitName = path.basename(fullPath, path.extname(fullPath)); @@ -51,6 +52,7 @@ export async function updateCurrentActiveUnitMCDCLines() { fullPath )); + vectorMessage(`enviroPath: ${enviroPath}, unitName: ${unitName}`); // Get all mcdc lines for every unit and parse it into JSON if (enviroPath) { // Replace single quotes with double quotes to make it a valid JSON string From 3a28f5f1a3d3b6ae19414fe01f683c7c22f6c537 Mon Sep 17 00:00:00 2001 From: Denis Moslavac Date: Tue, 13 Jan 2026 14:11:20 +0100 Subject: [PATCH 19/26] Changed debug log location --- src/editorDecorator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editorDecorator.ts b/src/editorDecorator.ts index 212602c2..e324d566 100644 --- a/src/editorDecorator.ts +++ b/src/editorDecorator.ts @@ -69,8 +69,8 @@ export async function updateCurrentActiveUnitMCDCLines() { // Check if there are no MCDC lines for the unit --> for example when the env is build with only Statement coverage // and the user changes it to Statement+MCDC in the settings vectorMessage(`MCDC LINES FOR UNIT: ${unitName}`); - vectorMessage(mcdcLinesForUnit.toString()); if (mcdcLinesForUnit) { + vectorMessage(mcdcLinesForUnit.toString()); currentActiveUnitMCDCLines = mcdcUnitCoverageLines[unitName]; } else { currentActiveUnitMCDCLines = []; From d21375c936862666b736cc1db63a2c61f5ff584f Mon Sep 17 00:00:00 2001 From: Denis Moslavac Date: Tue, 13 Jan 2026 17:41:05 +0100 Subject: [PATCH 20/26] Debugging logs for manage tests --- src/testPane.ts | 3 +++ src/vcastTestInterface.ts | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/testPane.ts b/src/testPane.ts index e7519e47..ef2c57d1 100644 --- a/src/testPane.ts +++ b/src/testPane.ts @@ -1835,8 +1835,11 @@ export async function refreshAllExtensionData() { // - we fall back from server mode // resetCoverageData(); + vectorMessage("-------------3---------------"); await buildTestPaneContents(); + vectorMessage("-------------4---------------"); await updateCOVdecorations(); + vectorMessage("-------------5---------------"); // Global varibale to see if we have a manage Project opened or just an Environment setGlobalProjectIsOpenedChecker(); setGlobalCompilerAndTestsuites(); diff --git a/src/vcastTestInterface.ts b/src/vcastTestInterface.ts index 0eb9b215..e512024d 100644 --- a/src/vcastTestInterface.ts +++ b/src/vcastTestInterface.ts @@ -907,7 +907,7 @@ export async function newEnvironment( // file in the list will be a C/C++ file but we need to filter // for the multi-select case. // - + vectorMessage("-------------0---------------"); let fileList: string[] = []; for (let index = 0; index < URIlist.length; index++) { const filePath = URIlist[index].fsPath; @@ -938,12 +938,14 @@ export async function newEnvironment( ); return; } + vectorMessage("-------------1---------------"); await configureWorkspaceAndBuildEnviro( fileList, tempEnvPath, projectEnvParameters ); } else { + vectorMessage("-------------1.5---------------"); let unitTestLocation = getUnitTestLocationForPath( path.dirname(fileList[0]) ); @@ -956,6 +958,7 @@ export async function newEnvironment( "]" ); } + vectorMessage("-------------2---------------"); await refreshAllExtensionData(); } From c7866f0b9be01726a86f2184a43854fda420d78a Mon Sep 17 00:00:00 2001 From: Denis Moslavac Date: Wed, 14 Jan 2026 09:20:35 +0100 Subject: [PATCH 21/26] Additional debugging logs --- src/vcastTestInterface.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/vcastTestInterface.ts b/src/vcastTestInterface.ts index e512024d..50d29cff 100644 --- a/src/vcastTestInterface.ts +++ b/src/vcastTestInterface.ts @@ -755,8 +755,11 @@ async function configureWorkspaceAndBuildEnviro( // If we have project params, we want to create an env within a project if (projectEnvParameters) { // Create the environment using the provided file list + vectorMessage("############## 0 ##############"); + vectorMessage(`envLocation: ${envLocation}`); + vectorMessage(`fileList: ${fileList.toString()}`); await commonEnvironmentSetup(fileList, envLocation, false); - + vectorMessage("############## 1 ##############"); const envName = createEnvNameFromFiles(fileList); const envFilePath = path.join(envLocation, `${envName}.env`); const testSuites = projectEnvParameters.testsuiteArgs; @@ -858,7 +861,8 @@ async function commonEnvironmentSetup( // Derive the environment name and path let enviroName = createEnvNameFromFiles(fileList)!.toUpperCase(); let enviroPath = path.join(envLocation, enviroName); - + vectorMessage(`enviroName: ${enviroName}`); + vectorMessage(`enviroPath 2: ${enviroPath}`); // If the directory already exists, prompt for a new name if (fs.existsSync(enviroPath)) { const response = await vscode.window.showInputBox({ @@ -885,7 +889,7 @@ async function commonEnvironmentSetup( return; } } - + vectorMessage("############## 2 ##############"); // Build the environment with the valid name await buildEnvironmentVCAST( fileList, From 1c29dff0e00bda2d4aece84c7ded9a9674a0c45a Mon Sep 17 00:00:00 2001 From: Denis Moslavac Date: Wed, 14 Jan 2026 09:52:43 +0100 Subject: [PATCH 22/26] Maximizing bottomBar --- src/vcastTestInterface.ts | 1 + tests/internal/e2e/test/specs/vcast_manage.test.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/vcastTestInterface.ts b/src/vcastTestInterface.ts index 50d29cff..414c2bd7 100644 --- a/src/vcastTestInterface.ts +++ b/src/vcastTestInterface.ts @@ -920,6 +920,7 @@ export async function newEnvironment( fileList.push(filePath); } } + vectorMessage(`FILELIST: ${fileList.toString()}`); if (fileList.length > 0) { if (projectEnvParameters) { // Get the workspace root folder. diff --git a/tests/internal/e2e/test/specs/vcast_manage.test.ts b/tests/internal/e2e/test/specs/vcast_manage.test.ts index 0b462eec..95a7b822 100644 --- a/tests/internal/e2e/test/specs/vcast_manage.test.ts +++ b/tests/internal/e2e/test/specs/vcast_manage.test.ts @@ -814,6 +814,7 @@ describe("vTypeCheck VS Code Extension", () => { const button = await $(`aria/Import OK`); await button.click(); console.log("Checking for Output logs if Environment creation is finished"); + await bottomBar.maximize(); await browser.waitUntil( async () => (await outputView.getText()) From 06a44917ca8908e03c38437f7c655ead139802ca Mon Sep 17 00:00:00 2001 From: Denis Moslavac Date: Wed, 14 Jan 2026 10:50:27 +0100 Subject: [PATCH 23/26] Restoring bottom bar --- tests/internal/e2e/test/specs/vcast_manage.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/internal/e2e/test/specs/vcast_manage.test.ts b/tests/internal/e2e/test/specs/vcast_manage.test.ts index 95a7b822..0260a42f 100644 --- a/tests/internal/e2e/test/specs/vcast_manage.test.ts +++ b/tests/internal/e2e/test/specs/vcast_manage.test.ts @@ -847,6 +847,8 @@ describe("vTypeCheck VS Code Extension", () => { const testsuiteNode = await findTreeNodeAtLevel(3, "DATABASE-MANAGER"); expect(testsuiteNode).toBeDefined(); + await bottomBar.restore(); + // Closing all current notifications for the next test const notificationsCenter = await workbench.openNotificationsCenter(); await notificationsCenter.clearAllNotifications(); From 5c2cc2f77117309db6071ba2f15fe7a80593cb69 Mon Sep 17 00:00:00 2001 From: Denis Moslavac Date: Wed, 14 Jan 2026 11:33:19 +0100 Subject: [PATCH 24/26] Removed debug logs --- src/testPane.ts | 3 --- src/vcastTestInterface.ts | 9 --------- 2 files changed, 12 deletions(-) diff --git a/src/testPane.ts b/src/testPane.ts index ef2c57d1..e7519e47 100644 --- a/src/testPane.ts +++ b/src/testPane.ts @@ -1835,11 +1835,8 @@ export async function refreshAllExtensionData() { // - we fall back from server mode // resetCoverageData(); - vectorMessage("-------------3---------------"); await buildTestPaneContents(); - vectorMessage("-------------4---------------"); await updateCOVdecorations(); - vectorMessage("-------------5---------------"); // Global varibale to see if we have a manage Project opened or just an Environment setGlobalProjectIsOpenedChecker(); setGlobalCompilerAndTestsuites(); diff --git a/src/vcastTestInterface.ts b/src/vcastTestInterface.ts index 414c2bd7..c8c3d31f 100644 --- a/src/vcastTestInterface.ts +++ b/src/vcastTestInterface.ts @@ -755,11 +755,7 @@ async function configureWorkspaceAndBuildEnviro( // If we have project params, we want to create an env within a project if (projectEnvParameters) { // Create the environment using the provided file list - vectorMessage("############## 0 ##############"); - vectorMessage(`envLocation: ${envLocation}`); - vectorMessage(`fileList: ${fileList.toString()}`); await commonEnvironmentSetup(fileList, envLocation, false); - vectorMessage("############## 1 ##############"); const envName = createEnvNameFromFiles(fileList); const envFilePath = path.join(envLocation, `${envName}.env`); const testSuites = projectEnvParameters.testsuiteArgs; @@ -889,7 +885,6 @@ async function commonEnvironmentSetup( return; } } - vectorMessage("############## 2 ##############"); // Build the environment with the valid name await buildEnvironmentVCAST( fileList, @@ -911,7 +906,6 @@ export async function newEnvironment( // file in the list will be a C/C++ file but we need to filter // for the multi-select case. // - vectorMessage("-------------0---------------"); let fileList: string[] = []; for (let index = 0; index < URIlist.length; index++) { const filePath = URIlist[index].fsPath; @@ -943,14 +937,12 @@ export async function newEnvironment( ); return; } - vectorMessage("-------------1---------------"); await configureWorkspaceAndBuildEnviro( fileList, tempEnvPath, projectEnvParameters ); } else { - vectorMessage("-------------1.5---------------"); let unitTestLocation = getUnitTestLocationForPath( path.dirname(fileList[0]) ); @@ -963,7 +955,6 @@ export async function newEnvironment( "]" ); } - vectorMessage("-------------2---------------"); await refreshAllExtensionData(); } From c446e82ca0cfce6641f07a302a87415b9d689c56 Mon Sep 17 00:00:00 2001 From: Denis Moslavac Date: Wed, 14 Jan 2026 13:34:09 +0100 Subject: [PATCH 25/26] Removed last debugging logs --- src/editorDecorator.ts | 5 ----- src/testPane.ts | 4 ++-- src/vcastTestInterface.ts | 4 +--- tests/internal/e2e/test/wdio.conf.ts | 2 +- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/editorDecorator.ts b/src/editorDecorator.ts index e324d566..20ede5d5 100644 --- a/src/editorDecorator.ts +++ b/src/editorDecorator.ts @@ -38,9 +38,7 @@ export async function updateCurrentActiveUnitMCDCLines() { if (activeEditor) { // First we need to get the env name from the active file const filePath = normalizePath(activeEditor.document.uri.fsPath); - vectorMessage(`filepath: ${filePath}`); let enviroPath = getEnvPathForFilePath(filePath); - vectorMessage(`enviroPath: ${enviroPath}`); // Get the unit name based on the file name without extension const fullPath = activeEditor.document.fileName; let unitName = path.basename(fullPath, path.extname(fullPath)); @@ -52,7 +50,6 @@ export async function updateCurrentActiveUnitMCDCLines() { fullPath )); - vectorMessage(`enviroPath: ${enviroPath}, unitName: ${unitName}`); // Get all mcdc lines for every unit and parse it into JSON if (enviroPath) { // Replace single quotes with double quotes to make it a valid JSON string @@ -68,9 +65,7 @@ export async function updateCurrentActiveUnitMCDCLines() { const mcdcLinesForUnit = mcdcUnitCoverageLines[unitName]; // Check if there are no MCDC lines for the unit --> for example when the env is build with only Statement coverage // and the user changes it to Statement+MCDC in the settings - vectorMessage(`MCDC LINES FOR UNIT: ${unitName}`); if (mcdcLinesForUnit) { - vectorMessage(mcdcLinesForUnit.toString()); currentActiveUnitMCDCLines = mcdcUnitCoverageLines[unitName]; } else { currentActiveUnitMCDCLines = []; diff --git a/src/testPane.ts b/src/testPane.ts index e7519e47..6aaacff1 100644 --- a/src/testPane.ts +++ b/src/testPane.ts @@ -652,10 +652,10 @@ export function addVcpEnvironments( environmentList.push({ projectPath: "", // VCPs are usually standalone or treated differently than managed envs buildDirectory: normalizedPath, // We use the VCP file path as the identifier - isBuilt: true, // VCPs are considered "non-built" / accessible + isBuilt: true, displayName: displayName, workspaceRoot: workspaceRoot, - isVcp: true, // Flag to identify this as a VCP node if needed downstream + isVcp: true, }); } } diff --git a/src/vcastTestInterface.ts b/src/vcastTestInterface.ts index c8c3d31f..1a977553 100644 --- a/src/vcastTestInterface.ts +++ b/src/vcastTestInterface.ts @@ -857,8 +857,7 @@ async function commonEnvironmentSetup( // Derive the environment name and path let enviroName = createEnvNameFromFiles(fileList)!.toUpperCase(); let enviroPath = path.join(envLocation, enviroName); - vectorMessage(`enviroName: ${enviroName}`); - vectorMessage(`enviroPath 2: ${enviroPath}`); + // If the directory already exists, prompt for a new name if (fs.existsSync(enviroPath)) { const response = await vscode.window.showInputBox({ @@ -914,7 +913,6 @@ export async function newEnvironment( fileList.push(filePath); } } - vectorMessage(`FILELIST: ${fileList.toString()}`); if (fileList.length > 0) { if (projectEnvParameters) { // Get the workspace root folder. diff --git a/tests/internal/e2e/test/wdio.conf.ts b/tests/internal/e2e/test/wdio.conf.ts index f82620b8..8799dc3e 100644 --- a/tests/internal/e2e/test/wdio.conf.ts +++ b/tests/internal/e2e/test/wdio.conf.ts @@ -424,7 +424,7 @@ export const config: Options.Testrunner = { const build_coverage = `cd ${workFolder} && bash ./c_cov_example.sh`; await executeCommand(build_coverage); - // No copy needed - everything is already in the right place! + // No copy needed - everything is put in place by the sh script } async function testManage(initialWorkdir: string) { From b23a5c4994a4d40c2fc183bece9f60d585fd6618 Mon Sep 17 00:00:00 2001 From: Denis Moslavac Date: Wed, 14 Jan 2026 13:38:53 +0100 Subject: [PATCH 26/26] Sonar --- src/testPane.ts | 2 +- tests/internal/e2e/test/specs/vcast_c_tests.test.ts | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/testPane.ts b/src/testPane.ts index 6aaacff1..df2cbc6a 100644 --- a/src/testPane.ts +++ b/src/testPane.ts @@ -643,7 +643,7 @@ export function addVcpEnvironments( workspaceRoot: string ): void { // Check if the cached data exists and has the 'vcp' key we added in Python - if (cachedWorkspaceEnvData && cachedWorkspaceEnvData.vcp) { + if (cachedWorkspaceEnvData?.vcp) { for (const vcpData of cachedWorkspaceEnvData.vcp) { // vcpData contains: { vcpPath, testData (empty), unitData, mockingSupport } const normalizedPath = normalizePath(vcpData.vcpPath); diff --git a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts index 1ccb090c..ac901074 100644 --- a/tests/internal/e2e/test/specs/vcast_c_tests.test.ts +++ b/tests/internal/e2e/test/specs/vcast_c_tests.test.ts @@ -6,15 +6,13 @@ import { } from "wdio-vscode-service"; import { Key } from "webdriverio"; import { - releaseCtrl, - executeCtrlClickOn, expandWorkspaceFolderSectionInExplorer, updateTestID, checkIfRequestInLogs, checkElementExistsInHTML, findTreeNodeAtLevel, + TIMEOUT, } from "../test_utils/vcast_utils"; -import { TIMEOUT } from "../test_utils/vcast_utils"; import { checkForServerRunnability } from "../../../../unit/getToolversion"; describe("vTypeCheck VS Code Extension", () => { @@ -112,7 +110,6 @@ describe("vTypeCheck VS Code Extension", () => { }); it("should check for vcp node", async () => { - const outputView = await bottomBar.openOutputView(); const activityBar = workbench.getActivityBar(); const testingView = await activityBar.getViewControl("Testing"); await testingView?.openView();