Skip to content

Commit afa1a25

Browse files
authored
Add ignoreStderr option to ignore stderr output in test results (#101)
When enabled, stderr is not automatically treated as test failure. Tests are marked as failed only if actual failure markers are detected.
1 parent 59a130d commit afa1a25

10 files changed

Lines changed: 101 additions & 5 deletions

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ Enable logging for debugging:
5353
- logpanel: Shows logs in VS Code's Output panel ("CppUTest Test Adapter Log").
5454
- logfile: Saves logs to a file. Use absolute paths and ensure the directory exists.
5555

56+
## Ignore Stderr
57+
By default, any output to stderr is treated as a test failure. If your tests produce warnings or logs on stderr without actually failing, you can disable this behavior:
58+
59+
```json
60+
{
61+
"cpputestTestAdapter.ignoreStderr": true
62+
}
63+
```
64+
- When `true`, stderr output is not automatically treated as test failure. Tests are marked as failed only if actual failure markers are detected in the output.
65+
5666
## Debugging
5767
To debug your tests, configure your launch.json like you would with any debugger (in this case gdb):
5868

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,12 @@
132132
"default": "objdump",
133133
"type": "string",
134134
"scope": "resource"
135+
},
136+
"cpputestTestAdapter.ignoreStderr": {
137+
"description": "Ignore stderr output when determining test result. When true, stderr is not treated as test failure",
138+
"default": false,
139+
"type": "boolean",
140+
"scope": "resource"
135141
}
136142
}
137143
}

src/Infrastructure/ExecutableRunner.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export class RunResult {
2222
export interface ExecutableRunnerOptions {
2323
workingDirectory?: string;
2424
objDumpExecutable?: string;
25+
ignoreStderr?: boolean;
2526
}
2627

2728
export default class ExecutableRunner {
@@ -31,6 +32,7 @@ export default class ExecutableRunner {
3132
private readonly command: string;
3233
private readonly workingDirectory: string;
3334
private readonly objDumpExecutable: string;
35+
private readonly ignoreStderr: boolean;
3436
private readonly tempFile: string;
3537
public readonly Name: string;
3638
private dumpCached: boolean;
@@ -49,6 +51,7 @@ export default class ExecutableRunner {
4951
this.workingDirectory = this.isEmptyString(wd) ? dirname(command) : wd!.trim();
5052

5153
this.objDumpExecutable = options?.objDumpExecutable ?? "objdump";
54+
this.ignoreStderr = options?.ignoreStderr ?? false;
5255
this.Name = basename(command);
5356
this.tempFile = `${this.Name}.dump`
5457
this.dumpCached = false;
@@ -148,7 +151,7 @@ export default class ExecutableRunner {
148151
console.error('stderr', error);
149152
reject(stderr);
150153
}
151-
if (stderr.trim() != "") {
154+
if (!this.ignoreStderr && stderr.trim() != "") {
152155
resolve(new RunResult(RunResultStatus.Error, stderr));
153156
} else if (error && error.code !== 0) {
154157
resolve(new RunResult(RunResultStatus.Failure, stdout));

src/Infrastructure/IWorkspaceConfiguration.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export interface IWorkspaceConfiguration {
88
debugLaunchConfigurationName: string | undefined;
99
objDumpExecutable: string | undefined;
1010
preLaunchTask: string;
11+
ignoreStderr: boolean;
1112
}

src/Infrastructure/SettingsProvider.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ export abstract class SettingsProvider {
2121
public abstract GetTestPath(): string;
2222
public abstract GetPreLaunchTask(): string;
2323
public abstract GetDebugConfiguration(): (IDebugConfiguration | undefined);
24-
public abstract GetWorkspaceFolders(): readonly IWorkspaceFolder[] | undefined
24+
public abstract GetWorkspaceFolders(): readonly IWorkspaceFolder[] | undefined;
25+
public abstract GetIgnoreStderr(): boolean;
2526
protected abstract GetCurrentFilename(): string
2627
protected abstract GetCurrentWorkspaceFolder(): string
2728
protected abstract GlobFiles(wildcardString: string): string[]

src/Infrastructure/VscodeSettingsProvider.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ export default class VscodeSettingsProvider extends SettingsProvider {
2424
testExecutable: wsConfig["testExecutable"],
2525
testExecutablePath: wsConfig["testExecutablePath"],
2626
testLocationFetchMode: wsConfig["testLocationFetchMode"],
27-
preLaunchTask: wsConfig["preLaunchTask"]
27+
preLaunchTask: wsConfig["preLaunchTask"],
28+
ignoreStderr: wsConfig["ignoreStderr"]
2829
}
2930
}
3031
})
@@ -54,6 +55,10 @@ export default class VscodeSettingsProvider extends SettingsProvider {
5455
return this.ResolveSettingsVariable(this.config.testExecutablePath);
5556
}
5657

58+
public GetIgnoreStderr(): boolean {
59+
return this.config.ignoreStderr ?? false;
60+
}
61+
5762
public GetDebugConfiguration(): (IDebugConfiguration | undefined) {
5863
// Thanks to: https://github.com/matepek/vscode-catch2-test-adapter/blob/9a2e9f5880ef3907d80ff99f3d6d028270923c95/src/Configurations.ts#L125
5964
if (vscode.workspace.workspaceFolders === undefined) {

src/adapter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ export class CppUTestAdapter implements TestAdapter {
147147
private GetExecutionOptions(): ExecutableRunnerOptions | undefined {
148148
return {
149149
objDumpExecutable: this.settingsProvider.GetObjDumpPath(),
150-
workingDirectory: this.settingsProvider.GetTestPath()
150+
workingDirectory: this.settingsProvider.GetTestPath(),
151+
ignoreStderr: this.settingsProvider.GetIgnoreStderr()
151152
}
152153
}
153154

tests/ExecutableRunner.spec.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,58 @@ describe("ExecutableRunner should", () => {
228228
expect(capturedOptions.cwd).to.equal(customWorkingDir);
229229
});
230230
});
231+
232+
describe("ignoreStderr option", () => {
233+
it("should return Error status when stderr is present and ignoreStderr is false", async () => {
234+
const log = mock<Log>();
235+
const stderrOutput = "some stderr warning";
236+
const processExecuter = setupMockCalls(undefined, "stdout output", stderrOutput);
237+
const command = "runnable";
238+
239+
const runner = new ExecutableRunner(processExecuter, command, log, { ignoreStderr: false });
240+
const result = await runner.RunTest("myGroup", "myTest");
241+
242+
expect(result).to.be.deep.equal(new RunResult(RunResultStatus.Error, stderrOutput));
243+
});
244+
245+
it("should return Error status when stderr is present and ignoreStderr is not specified", async () => {
246+
const log = mock<Log>();
247+
const stderrOutput = "some stderr warning";
248+
const processExecuter = setupMockCalls(undefined, "stdout output", stderrOutput);
249+
const command = "runnable";
250+
251+
const runner = new ExecutableRunner(processExecuter, command, log);
252+
const result = await runner.RunTest("myGroup", "myTest");
253+
254+
expect(result).to.be.deep.equal(new RunResult(RunResultStatus.Error, stderrOutput));
255+
});
256+
257+
it("should ignore stderr and return Success when ignoreStderr is true and test passes", async () => {
258+
const log = mock<Log>();
259+
const stdoutOutput = "TEST(myGroup, myTest) - 0 ms";
260+
const stderrOutput = "some stderr warning";
261+
const processExecuter = setupMockCalls(undefined, stdoutOutput, stderrOutput);
262+
const command = "runnable";
263+
264+
const runner = new ExecutableRunner(processExecuter, command, log, { ignoreStderr: true });
265+
const result = await runner.RunTest("myGroup", "myTest");
266+
267+
expect(result).to.be.deep.equal(new RunResult(RunResultStatus.Success, stdoutOutput));
268+
});
269+
270+
it("should ignore stderr and return Failure when ignoreStderr is true and test fails", async () => {
271+
const log = mock<Log>();
272+
const stdoutOutput = "TEST(myGroup, myTest) failed";
273+
const stderrOutput = "some stderr warning";
274+
const processExecuter = setupMockCalls(new ExecError(1), stdoutOutput, stderrOutput);
275+
const command = "runnable";
276+
277+
const runner = new ExecutableRunner(processExecuter, command, log, { ignoreStderr: true });
278+
const result = await runner.RunTest("myGroup", "myTest");
279+
280+
expect(result).to.be.deep.equal(new RunResult(RunResultStatus.Failure, stdoutOutput));
281+
});
282+
});
231283
})
232284

233285
function setupMockCalls(error: ExecException | undefined, returnValue: string, errorValue: string) {

tests/RegexResultParser.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,17 @@ describe("RegexResultParser should", () => {
4343
expect(resultParser.GetResult(new RunResult(statusFromRunner, stringFromRunner))).to.be.deep.eq(expectedTestResult);
4444
})
4545
})
46+
47+
describe("ParseResultError", () => {
48+
it("should treat stderr as failure", () => {
49+
const resultParser = new RegexResultParser();
50+
const stderrOutput = "Some warning output to stderr";
51+
const runResult = new RunResult(RunResultStatus.Error, stderrOutput);
52+
53+
const result = resultParser.GetResult(runResult);
54+
55+
expect(result.state).to.equal(TestState.Failed);
56+
expect(result.message).to.equal(stderrOutput);
57+
});
58+
});
4659
});

tests/SettingsProvider.spec.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ class TestSettingsProvider extends SettingsProvider {
4747
uri: "."
4848
}];
4949
}
50+
GetIgnoreStderr(): boolean {
51+
return this.config.ignoreStderr ?? false;
52+
}
5053
protected GetCurrentFilename(): string {
5154
return "myFile.c";
5255
}
@@ -74,7 +77,8 @@ describe("SettingsProvider should", () => {
7477
testExecutable: "",
7578
testExecutablePath: "",
7679
testLocationFetchMode: "",
77-
preLaunchTask: ""
80+
preLaunchTask: "",
81+
ignoreStderr: false
7882
};
7983
let filesToFind = [""];
8084

0 commit comments

Comments
 (0)