Skip to content
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
89def45
Build the necessary targets prior to running tests.
Jul 22, 2025
3acf209
Merge branch 'microsoft:main' into building-tests
epistax Jul 22, 2025
9e6cdcf
Cleaned up change log and ctest impl a bit.
Jul 22, 2025
d548f90
Fix build-before-test: correct target name resolution and error repor…
mcodilla Apr 7, 2026
7fec8a3
Revert "Fix build-before-test: correct target name resolution and err…
mcodilla Apr 13, 2026
8dc16aa
Merge branch 'main' of https://github.com/microsoft/vscode-cmake-tool…
mcodilla Apr 13, 2026
66c3263
Closing brace
mcodilla Apr 13, 2026
8195cc6
Readd these
mcodilla Apr 13, 2026
c5c3485
Compute the target name instead of the executable
mcodilla Apr 13, 2026
6934a68
Merge branch 'main' into building-tests2
hanniavalera Apr 13, 2026
2ecb65b
Merge branch 'main' into building-tests2
hanniavalera Apr 15, 2026
fb2f7c0
Merge branch 'main' into building-tests2
hanniavalera Apr 15, 2026
3ae3c12
Fix typo in variable name
mcodilla Apr 20, 2026
632b758
Update src/ctest.ts
mcodilla Apr 20, 2026
f818aaa
Merge branch 'building-tests2' of https://github.com/microsoft/vscode…
mcodilla Apr 20, 2026
ea4ee78
Use a precomputed map
mcodilla Apr 20, 2026
ddfb2a9
Merge branch 'main' into building-tests2
hanniavalera Apr 20, 2026
1398c4e
Update src/ctest.ts
mcodilla Apr 20, 2026
16a631c
Merge branch 'main' into building-tests2
hanniavalera Apr 21, 2026
5e17719
fix log target names and exit code when build-before-test fails
mcodilla Apr 23, 2026
b6feb7c
Merge branch 'building-tests2' of https://github.com/microsoft/vscode…
mcodilla Apr 23, 2026
1fe7873
Merge branch 'main' into building-tests2
mcodilla Apr 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Features:
- Add support for the FASTBuild generator (CMake 4.2+). [#4690](https://github.com/microsoft/vscode-cmake-tools/pull/4690)
- Add support for `${workspaceFolder}`, `${workspaceFolder:name}` variables and relative paths in `cmake.exclude` setting for multi-root workspaces. [#4689](https://github.com/microsoft/vscode-cmake-tools/pull/4689)

Improvements:
- When CMake is invoked prior to running tests, build targets required for the test rather than everything. [#4515](https://github.com/microsoft/vscode-cmake-tools/issues/4515) [@epistax](https://github.com/epistax)

Bug Fixes:
- Fix kit detection returning "unknown vendor" when using clang-cl compiler. [#4638](https://github.com/microsoft/vscode-cmake-tools/issues/4638)
- Update testing framework to fix bugs when running tests of CMake Tools without a reliable internet connection. [#4891](https://github.com/microsoft/vscode-cmake-tools/pull/4891) [@cwalther](https://github.com/cwalther)
Expand Down
93 changes: 92 additions & 1 deletion src/ctest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1832,6 +1832,10 @@ export class CTestDriver implements vscode.Disposable {
return currentTestItem.id;
}

/**
* Determine and build all targets needed to rebuild the selected TestItems. Returns a false if anything goes
* wrong, and returns an early success if build-before-run is disabled.
Comment thread
hanniavalera marked this conversation as resolved.
*/
private async buildTests(tests: vscode.TestItem[], run: vscode.TestRun): Promise<boolean> {
// If buildBeforeRun is set to false, we skip the build step
if (!this.ws.config.buildBeforeRun) {
Expand All @@ -1841,7 +1845,11 @@ export class CTestDriver implements vscode.Disposable {
// Folder => status
const builtFolder = new Map<string, number>();
let status: number = 0;
const foundTarget = new Map<CMakeProject, Map<string, vscode.TestItem[]>>();
for (const test of tests) {
if (!await this.getTestTargets(test, foundTarget, run)) {
return false;
}
const folder = this.getTestRootFolder(test);
if (!builtFolder.has(folder)) {
const project = await this.projectController?.getProjectForFolder(folder);
Expand Down Expand Up @@ -1869,7 +1877,90 @@ export class CTestDriver implements vscode.Disposable {
}
}

return Array.from(builtFolder.values()).filter(v => v !== 0).length === 0;
return this.buildTestTargets(foundTarget, run);
Comment thread
hanniavalera marked this conversation as resolved.
Comment thread
hanniavalera marked this conversation as resolved.
}

/**
* Given the TestItem, determine the owning CMakeProject and build targets to build the tests. If the given
* TestItem is a suite, then recurse. Information is passed back through the foundTarget parameter. A failure to
* identify the project of the test will result in a ctest error and a false value being returned.
*/
private async getTestTargets(test: vscode.TestItem, foundTarget: Map<CMakeProject, Map<string, vscode.TestItem[]>>, run: vscode.TestRun): Promise<boolean> {
if (test.children.size > 0) {
const children = this.testItemCollectionToArray(test.children);
for (const child of children) {
if (!await this.getTestTargets(child, foundTarget, run)) {
return false;
}
}
} else {
const testProgram = this.testProgram(test.id);
Comment thread
mcodilla marked this conversation as resolved.
if (!testProgram) {
this.ctestErrored(test, run, { message: localize('test.program.not.found', 'Could not determine the test program for test {0}', test.id) });
return false;
}
const folder = this.getTestRootFolder(test);
const project = await this.projectController?.getProjectForFolder(folder);
if (!project) {
this.ctestErrored(test, run, { message: localize('no.project.found', 'No project found for folder {0}', folder) });
return false;
}
if (!foundTarget.has(project)) {
foundTarget.set(project, new Map<string, vscode.TestItem[]>([[testProgram, [test]]]));
} else {
const prj = foundTarget.get(project)!;
if (!prj.has(testProgram)) {
prj.set(testProgram, [test]);
} else {
prj.get(testProgram)!.push(test);
}
}
}
return true;
}

/**
* Build the targets provided in foundTarget. CMake will be invoked once per CMakeProject for efficiency. On error,
* the associated tests will be flagged with a ctest error and a false value will be returned.
*/
private async buildTestTargets(foundTarget: Map<CMakeProject, Map<string, vscode.TestItem[]>>, run: vscode.TestRun): Promise<boolean> {
let overallSuccess = true;
Comment thread
hanniavalera marked this conversation as resolved.
for (const [project, targets] of foundTarget) {
const execTargets = await project.executableTargets;
// Precompute a lookup map from normalized executable path to target name
const execPathToName = new Map<string, string>();
for (const t of execTargets) {
execPathToName.set(util.platformNormalizePath(t.path), t.name);
}
const accumulatedTestList: vscode.TestItem[] = [];
const accumulatedTargets: string[] = [];
let success: boolean = true;
for (const [targetPath, testList] of targets) {
const normalizedTargetPath = util.platformNormalizePath(targetPath);
accumulatedTargets.push(execPathToName.get(normalizedTargetPath) ?? path.parse(targetPath).name);
accumulatedTestList.push(...testList);
}
try {
if (extensionManager !== undefined && extensionManager !== null) {
extensionManager.cleanOutputChannel();
}
const buildResult = await project.build(accumulatedTargets, false, false);
Comment thread
hanniavalera marked this conversation as resolved.
if (buildResult.exitCode !== 0) {
log.error(localize('build.targets.failed.with.code', 'Building targets [{0}] failed with exit code {1}.', accumulatedTargets.join(', '), buildResult.exitCode));
success = false;
}
} catch (e) {
log.error(localize('build.targets.threw', 'Building targets [{0}] threw an error: {1}', accumulatedTargets.join(', '), (e as Error)?.message ?? String(e)));
success = false;
}
Comment thread
mcodilla marked this conversation as resolved.
if (!success) {
overallSuccess = false;
accumulatedTestList.forEach(test => {
this.ctestErrored(test, run, { message: localize('build.failed', 'Build failed') });
});
}
};
Comment thread
hanniavalera marked this conversation as resolved.
return overallSuccess;
}

/**
Expand Down
Loading