Skip to content

Commit beb7ef9

Browse files
authored
Merge pull request #146 from NJGenerac/feature/ceedling-1.0-support
Add support for Ceedling 1.0+ report_tests_log_factory plugin
2 parents 6d2d2ed + 7c4fc34 commit beb7ef9

File tree

5 files changed

+369
-14
lines changed

5 files changed

+369
-14
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
77

88
## [Unreleased]
99

10+
### Added
11+
12+
* Add support for Ceedling 1.0+ `report_tests_log_factory` plugin with CppUnit format.
13+
* Add `ceedlingExplorer.debugTestExecutablePath` command that returns the full path to test executable.
14+
* Add `isCeedling1Plus()` helper method for reliable Ceedling 1.0+ detection using plugin configuration.
15+
* Add configuration documentation for both Ceedling versions in README.
16+
17+
### Fixed
18+
19+
* Fix compatibility with Ceedling 1.0+ (addresses issues #137 and #145).
20+
* Fix debug executable path detection for Ceedling 1.0+ by checking for `report_tests_log_factory` plugin instead of relying on version string parsing.
21+
* Ensure test executables in subdirectories (e.g., `test_name/test_name.out`) are correctly located for debugging.
22+
1023
## [1.12.0] - 2024-01-02
1124

1225
### Added

README.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ Run your [Ceedling](https://github.com/ThrowTheSwitch/Ceedling) tests using the
2121
* Open the workspace or folder containing your Ceedling project
2222
* Configure your `project.yml` path in the VS Code's settings if required [see below](#options)
2323
* Configure the shell path where Ceedling is installed in the VS Code's settings if required (It might be required on Windows) [see below](#options)
24-
* Enable the `xml_tests_report` Ceedling plugin in your `project.yml` [see the Ceedling doc](https://github.com/ThrowTheSwitch/Ceedling/blob/master/docs/CeedlingPacket.md#tool-element-runtime-substitution-notational-substitution)
24+
* Enable the appropriate Ceedling XML report plugin in your `project.yml`:
25+
* **Ceedling 0.31.x**: Enable the `xml_tests_report` plugin [see the Ceedling doc](https://github.com/ThrowTheSwitch/Ceedling/blob/master/docs/CeedlingPacket.md#tool-element-runtime-substitution-notational-substitution)
26+
* **Ceedling 1.0+**: Enable the `report_tests_log_factory` plugin with `cppunit` report format (see [Configuration Examples](#ceedling-plugin-configuration))
2527
* Open the Test view
2628
* Run your tests using the ![Run](img/run.png) icons in the Test Explorer or the CodeLenses in your test file
2729

@@ -92,6 +94,41 @@ Example pattern object (GCC compiler warnings):
9294
}
9395
```
9496

97+
### Ceedling Plugin Configuration
98+
99+
This extension supports both Ceedling 0.31.x and Ceedling 1.0+ by accepting either the legacy `xml_tests_report` plugin or the new `report_tests_log_factory` plugin with CppUnit format.
100+
101+
#### Ceedling 0.31.x Configuration
102+
103+
```yaml
104+
:plugins:
105+
:enabled:
106+
- xml_tests_report
107+
108+
# Optional: customize report filename
109+
:xml_tests_report:
110+
:artifact_filename: report.xml # default
111+
```
112+
113+
#### Ceedling 1.0+ Configuration
114+
115+
```yaml
116+
:plugins:
117+
:enabled:
118+
- report_tests_log_factory
119+
120+
:report_tests_log_factory:
121+
:reports:
122+
- cppunit # Required for Test Explorer
123+
124+
# Optional: customize report filename
125+
:report_tests_log_factory:
126+
:cppunit:
127+
:filename: cppunit_tests_report.xml # default
128+
```
129+
130+
**Note**: The extension requires the **CppUnit XML format** specifically. While `report_tests_log_factory` can generate multiple report formats (JUnit, JSON, HTML), only the CppUnit format is compatible with this extension.
131+
95132
## Commands
96133

97134
The following commands are available in VS Code's command palette, use the ID to add them to your keyboard shortcuts:

src/adapter.ts

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export class CeedlingAdapter implements TestAdapter {
3737
private fileLabelRegex: RegExp | undefined;
3838
private testLabelRegex: RegExp | undefined;
3939
private debugTestExecutable: string = '';
40+
private debugTestExecutablePath: string = '';
4041
private buildDirectory: string = '';
4142
private reportFilename: string = '';
4243
private watchedFileForAutorunList: string[] = [];
@@ -182,11 +183,12 @@ export class CeedlingAdapter implements TestAdapter {
182183
const testFileName = `${/([^/]*).c$/.exec(testToExec)![1]}`;
183184

184185
// Set current test executable
185-
const ceedlingVersion = await this.getCeedlingVersion();
186-
if (this.detectTestSpecificDefines(ymlProjectData, testFileName) || semver.satisfies(ceedlingVersion, ">0.31.1"))
187-
this.setDebugTestExecutable(`${testFileName}/${testFileName}${ext}`);
188-
else
189-
this.setDebugTestExecutable(`${testFileName}${ext}`);
186+
// Use subdirectory format for Ceedling 1.0+ or tests with specific defines
187+
const useSubdirectory = this.isCeedling1Plus(ymlProjectData) || this.detectTestSpecificDefines(ymlProjectData, testFileName);
188+
const executableRelPath = useSubdirectory ? `${testFileName}/${testFileName}${ext}` : `${testFileName}${ext}`;
189+
190+
this.setDebugTestExecutable(executableRelPath);
191+
this.setDebugTestExecutablePath(`${this.buildDirectory}/test/out/${executableRelPath}`);
190192

191193
// Launch debugger
192194
if (!await vscode.debug.startDebugging(this.workspaceFolder, debugConfiguration))
@@ -195,6 +197,7 @@ export class CeedlingAdapter implements TestAdapter {
195197
finally {
196198
// Reset current test executable
197199
this.setDebugTestExecutable("");
200+
this.setDebugTestExecutablePath("");
198201
}
199202
}
200203

@@ -207,6 +210,15 @@ export class CeedlingAdapter implements TestAdapter {
207210
this.logger.info(`Set the debugTestExecutable to ${this.debugTestExecutable}`);
208211
}
209212

213+
getDebugTestExecutablePath(): string {
214+
return this.debugTestExecutablePath;
215+
}
216+
217+
setDebugTestExecutablePath(path: string) {
218+
this.debugTestExecutablePath = path;
219+
this.logger.info(`Set the debugTestExecutablePath to ${this.debugTestExecutablePath}`);
220+
}
221+
210222
async clean(): Promise<void> {
211223
this.logger.trace(`clean()`);
212224
const result = await vscode.window.withProgress(
@@ -284,14 +296,30 @@ export class CeedlingAdapter implements TestAdapter {
284296
`Please check the ceedlingExplorer.projectPath option.`;
285297
}
286298
try {
287-
if (!ymlProjectData[':plugins'][':enabled'].includes('xml_tests_report')) {
299+
const hasXmlTestsReport = ymlProjectData[':plugins'][':enabled'].includes('xml_tests_report');
300+
const hasReportFactory = ymlProjectData[':plugins'][':enabled'].includes('report_tests_log_factory');
301+
302+
if (!hasXmlTestsReport && !hasReportFactory) {
288303
throw 'Xml report plugin not enabled';
289304
}
305+
306+
// For report_tests_log_factory, verify cppunit format is enabled
307+
if (hasReportFactory && !hasXmlTestsReport) {
308+
try {
309+
const reports = ymlProjectData[':report_tests_log_factory'][':reports'];
310+
if (!reports || !reports.includes('cppunit')) {
311+
throw 'CppUnit report not enabled in report_tests_log_factory';
312+
}
313+
} catch (e) {
314+
return `The 'report_tests_log_factory' plugin is enabled but 'cppunit' report format is not configured. ` +
315+
`Add 'cppunit' to :report_tests_log_factory::reports list in your project.yml file.`;
316+
}
317+
}
290318
} catch (e) {
291-
return `The required Ceedling plugin 'xml_tests_report' is not enabled. ` +
292-
`You have to edit your 'project.xml' file to enable the plugin.\n` +
293-
`see https://github.com/ThrowTheSwitch/Ceedling/blob/master/docs/CeedlingPacket.md` +
294-
`#tool-element-runtime-substitution-notational-substitution`;
319+
return `A required Ceedling XML report plugin is not enabled. ` +
320+
`For Ceedling 0.31.x, enable 'xml_tests_report' plugin. ` +
321+
`For Ceedling 1.0+, enable 'report_tests_log_factory' plugin with 'cppunit' report format.\n` +
322+
`see https://github.com/ThrowTheSwitch/Ceedling/blob/master/docs/CeedlingPacket.md`;
295323
}
296324
}
297325

@@ -331,7 +359,11 @@ export class CeedlingAdapter implements TestAdapter {
331359
return value.startsWith(" - ");
332360
}).map((value: string) => {
333361
return value.substr(3).trim();
334-
})
362+
}).filter((filePath: string) => {
363+
// Exclude files from the build output directory (preprocessed files, runners, etc.)
364+
// These would create duplicate entries in the test explorer
365+
return !filePath.includes(this.buildDirectory);
366+
});
335367
}
336368
} finally {
337369
release();
@@ -386,6 +418,15 @@ export class CeedlingAdapter implements TestAdapter {
386418
return false;
387419
}
388420

421+
private isCeedling1Plus(ymlProjectData: any = undefined): boolean {
422+
if (ymlProjectData) {
423+
try {
424+
return ymlProjectData[':plugins'][':enabled'].includes('report_tests_log_factory');
425+
} catch (e) { }
426+
}
427+
return false;
428+
}
429+
389430
private async getCeedlingVersion(): Promise<string> {
390431
const result = await this.execCeedling(['version']);
391432
const regex = new RegExp('^\\s*Ceedling::\\s*(.*)$', 'gm');
@@ -481,12 +522,28 @@ export class CeedlingAdapter implements TestAdapter {
481522
private setXmlReportPath(ymlProjectData: any = undefined) {
482523
let reportFilename = 'report.xml';
483524
if (ymlProjectData) {
525+
// Try new Ceedling 1.0+ report_tests_log_factory plugin first
484526
try {
485-
const ymlProjectReportFilename = ymlProjectData[':xml_tests_report'][':artifact_filename'];
527+
const ymlProjectReportFilename = ymlProjectData[':report_tests_log_factory'][':cppunit'][':filename'];
486528
if (ymlProjectReportFilename != undefined) {
487529
reportFilename = ymlProjectReportFilename;
488530
}
489-
} catch (e) { }
531+
} catch (e) {
532+
// Fall back to old xml_tests_report plugin (Ceedling 0.31.x)
533+
try {
534+
const ymlProjectReportFilename = ymlProjectData[':xml_tests_report'][':artifact_filename'];
535+
if (ymlProjectReportFilename != undefined) {
536+
reportFilename = ymlProjectReportFilename;
537+
}
538+
} catch (e) {
539+
// If report_tests_log_factory is enabled but no custom filename, use default
540+
try {
541+
if (ymlProjectData[':plugins'][':enabled'].includes('report_tests_log_factory')) {
542+
reportFilename = 'cppunit_tests_report.xml';
543+
}
544+
} catch (e) { }
545+
}
546+
}
490547
}
491548
this.reportFilename = reportFilename;
492549
}

src/main.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@ function debugTestExecutable(): string | null {
2323
return null;
2424
}
2525

26+
function debugTestExecutablePath(): string | null {
27+
if (!adapters) return null;
28+
for (let adapter of adapters) {
29+
let debugTestExecutablePath = adapter.getDebugTestExecutablePath();
30+
if (debugTestExecutablePath) {
31+
return debugTestExecutablePath;
32+
}
33+
}
34+
logger.showError("No debug test executable path found");
35+
logger.showInfo(
36+
"A debug configuration with a path containing `${command:ceedlingExplorer.debugTestExecutablePath}` " +
37+
"cannot be started from F5 or the Run pannel. It should be started from a bug icon in the Test pannel."
38+
);
39+
return null;
40+
}
41+
2642
function ceedlingClean(): void {
2743
if (!adapters) return;
2844
for (let adapter of adapters) {
@@ -41,6 +57,7 @@ export async function activate(context: vscode.ExtensionContext) {
4157
const testExplorerExtension = vscode.extensions.getExtension<TestHub>(testExplorerExtensionId);
4258
if (testExplorerExtension) {
4359
context.subscriptions.push(vscode.commands.registerCommand("ceedlingExplorer.debugTestExecutable", debugTestExecutable));
60+
context.subscriptions.push(vscode.commands.registerCommand("ceedlingExplorer.debugTestExecutablePath", debugTestExecutablePath));
4461
context.subscriptions.push(vscode.commands.registerCommand("ceedlingExplorer.clean", ceedlingClean));
4562
context.subscriptions.push(vscode.commands.registerCommand("ceedlingExplorer.clobber", ceedlingClobber));
4663
context.subscriptions.push(logger);

0 commit comments

Comments
 (0)