Skip to content

Commit a69ba2a

Browse files
committed
Change the test to read from file instead of exit code
1 parent ad01d4a commit a69ba2a

4 files changed

Lines changed: 91 additions & 52 deletions

File tree

Extension/src/common.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,34 @@ export function hasMsvcEnvironment(): boolean {
15681568
);
15691569
}
15701570

1571+
export function getMissingMsvcEnvironmentVariables(): string[] {
1572+
const msvcEnvVars: string[] = [
1573+
'DevEnvDir',
1574+
'Framework40Version',
1575+
'FrameworkDir',
1576+
'FrameworkVersion',
1577+
'INCLUDE',
1578+
'LIB',
1579+
'LIBPATH',
1580+
'UCRTVersion',
1581+
'UniversalCRTSdkDir',
1582+
'VCIDEInstallDir',
1583+
'VCINSTALLDIR',
1584+
'VCToolsRedistDir',
1585+
'VisualStudioVersion',
1586+
'VSINSTALLDIR',
1587+
'WindowsLibPath',
1588+
'WindowsSdkBinPath',
1589+
'WindowsSdkDir',
1590+
'WindowsSDKLibVersion',
1591+
'WindowsSDKVersion'
1592+
];
1593+
return msvcEnvVars.filter(envVarName =>
1594+
(process.env[envVarName] === undefined || process.env[envVarName] === '') &&
1595+
extensionContext?.environmentVariableCollection?.get(envVarName) === undefined
1596+
);
1597+
}
1598+
15711599
function isIntegral(str: string): boolean {
15721600
const regex = /^-?\d+$/;
15731601
return regex.test(str);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include <fstream>
2+
3+
int main() {
4+
std::ofstream resultFile("runWithoutDebuggingResult.txt");
5+
if (!resultFile) {
6+
return 1;
7+
}
8+
9+
resultFile << 37;
10+
return 0;
11+
}

Extension/test/scenarios/RunWithoutDebugging/assets/exitCode.cpp

Lines changed: 0 additions & 3 deletions
This file was deleted.

Extension/test/scenarios/RunWithoutDebugging/tests/runWithoutDebugging.integration.test.ts

Lines changed: 52 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ interface TrackerState {
2424
stoppedEventReceived: boolean;
2525
exitedEventReceived: boolean;
2626
exitedBeforeStop: boolean;
27-
actualExitCode?: number;
2827
}
2928

3029
interface TrackerController {
@@ -59,7 +58,8 @@ async function setWindowsBuildEnvironment(): Promise<void> {
5958
}, 1000);
6059
await promise;
6160
clearInterval(timer);
62-
assert.strictEqual(util.hasMsvcEnvironment(), true, 'MSVC environment not set correctly.');
61+
const missingVars = util.getMissingMsvcEnvironmentVariables();
62+
assert.strictEqual(missingVars.length, 0, `MSVC environment missing: ${missingVars.join(', ')}`);
6363
}
6464

6565
async function compileProgram(workspacePath: string, sourcePath: string, outputPath: string): Promise<void> {
@@ -86,11 +86,11 @@ async function compileProgram(workspacePath: string, sourcePath: string, outputP
8686
assert.fail(`Unsupported test platform: ${process.platform}`);
8787
}
8888

89-
async function createBreakpointAtReturnStatement(sourceUri: vscode.Uri): Promise<vscode.SourceBreakpoint> {
89+
async function createBreakpointAtResultWriteStatement(sourceUri: vscode.Uri): Promise<vscode.SourceBreakpoint> {
9090
const document = await vscode.workspace.openTextDocument(sourceUri);
91-
const returnLine = document.getText().split(/\r?\n/).findIndex((line) => line.includes('return 37;'));
92-
assert.notStrictEqual(returnLine, -1, 'Unable to find expected return statement for breakpoint placement.');
93-
const breakpoint = new vscode.SourceBreakpoint(new vscode.Location(sourceUri, new vscode.Position(returnLine, 0)), true);
91+
const resultWriteLine = document.getText().split(/\r?\n/).findIndex((line) => line.includes('resultFile << 37;'));
92+
assert.notStrictEqual(resultWriteLine, -1, 'Unable to find expected result-write statement for breakpoint placement.');
93+
const breakpoint = new vscode.SourceBreakpoint(new vscode.Location(sourceUri, new vscode.Position(resultWriteLine, 0)), true);
9494
vscode.debug.addBreakpoints([breakpoint]);
9595
return breakpoint;
9696
}
@@ -106,7 +106,7 @@ function createSessionTerminatedPromise(sessionName: string): Promise<void> {
106106
});
107107
}
108108

109-
function createTracker(debugType: string, sessionName: string, programName: string, timeoutMs: number, timeoutMessage: string): TrackerController {
109+
function createTracker(debugType: string, sessionName: string, timeoutMs: number, timeoutMessage: string): TrackerController {
110110
const state: TrackerState = {
111111
setBreakpointsRequestReceived: false,
112112
stoppedEventReceived: false,
@@ -150,37 +150,8 @@ function createTracker(debugType: string, sessionName: string, programName: stri
150150
resolve('stopped');
151151
}
152152

153-
// integratedTerminal scenarios may not send an 'exited' event if the terminal does not support shell integration.
154-
// We have to close the terminal with the exit code to get the result.
155-
if (message.event === 'terminated' && !state.exitedEventReceived) {
153+
if ((message.event === 'terminated' || message.event === 'exited') && !state.exitedEventReceived) {
156154
state.exitedEventReceived = true;
157-
const disp = vscode.window.onDidCloseTerminal((terminal) => {
158-
if (terminal.name === programName) {
159-
state.exitedEventReceived = true;
160-
state.actualExitCode = terminal.exitStatus?.code;
161-
if (!state.stoppedEventReceived) {
162-
state.exitedBeforeStop = true;
163-
}
164-
if (timeoutHandle) {
165-
clearTimeout(timeoutHandle);
166-
timeoutHandle = undefined;
167-
}
168-
disp.dispose();
169-
resolve('exited');
170-
}
171-
});
172-
173-
vscode.window.terminals.forEach((terminal) => {
174-
if (terminal.name === programName) {
175-
const exitCommand = isWindows ? 'exit /b %ErrorLevel%' : 'exit $?';
176-
terminal.sendText(exitCommand);
177-
}
178-
});
179-
}
180-
181-
if (message.event === 'exited') {
182-
state.exitedEventReceived = true;
183-
state.actualExitCode = message.body?.exitCode;
184155
if (!state.stoppedEventReceived) {
185156
state.exitedBeforeStop = true;
186157
}
@@ -210,6 +181,32 @@ function createTracker(debugType: string, sessionName: string, programName: stri
210181
};
211182
}
212183

184+
async function waitForResultFileValue(filePath: string, timeoutMs: number): Promise<number> {
185+
const deadline = Date.now() + timeoutMs;
186+
let lastContents = '';
187+
188+
while (Date.now() < deadline) {
189+
try {
190+
lastContents = await util.readFileText(filePath, 'utf8');
191+
const trimmedContents = lastContents.trim();
192+
if (trimmedContents.length > 0) {
193+
const value = Number.parseInt(trimmedContents, 10);
194+
if (!Number.isNaN(value)) {
195+
return value;
196+
}
197+
}
198+
} catch (error) {
199+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
200+
throw error;
201+
}
202+
}
203+
204+
await new Promise<void>(resolve => setTimeout(resolve, 100));
205+
}
206+
207+
assert.fail(`Timed out waiting for numeric result in ${filePath}. Last contents: ${lastContents}`);
208+
}
209+
213210
suite('Run Without Debugging Integration Test', function (): void {
214211
suiteSetup(async function (): Promise<void> {
215212
const extension: vscode.Extension<any> = vscode.extensions.getExtension('ms-vscode.cpptools') || assert.fail('Extension not found');
@@ -224,21 +221,23 @@ suite('Run Without Debugging Integration Test', function (): void {
224221
}
225222
});
226223

227-
test('Run Without Debugging should not break on breakpoints and emit expected exit code', async () => {
228-
const expectedExitCode = 37;
224+
test('Run Without Debugging should not break on breakpoints and write the expected result file', async () => {
225+
const expectedResultValue = 37;
229226
const workspaceFolder = vscode.workspace.workspaceFolders?.[0] ?? assert.fail('No workspace folder available');
230227
const workspacePath = workspaceFolder.uri.fsPath;
231-
const sourceFile = path.join(workspacePath, 'exitCode.cpp');
228+
const sourceFile = path.join(workspacePath, 'debugTest.cpp');
232229
const sourceUri = vscode.Uri.file(sourceFile);
233-
const executableName = isWindows ? 'exitCodeProgram.exe' : 'exitCodeProgram';
230+
const resultFilePath = path.join(workspacePath, 'runWithoutDebuggingResult.txt');
231+
const executableName = isWindows ? 'debugTestProgram.exe' : 'debugTestProgram';
234232
const executablePath = path.join(workspacePath, executableName);
235-
const sessionName = 'Run Without Debugging Exit Code';
233+
const sessionName = 'Run Without Debugging Result File';
236234
const debugType = isWindows ? 'cppvsdbg' : 'cppdbg';
237235

236+
await util.deleteFile(resultFilePath);
238237
await compileProgram(workspacePath, sourceFile, executablePath);
239238

240-
const breakpoint = await createBreakpointAtReturnStatement(sourceUri);
241-
const tracker = createTracker(debugType, sessionName, executablePath, 30000, 'Timed out waiting for debugger event.');
239+
const breakpoint = await createBreakpointAtResultWriteStatement(sourceUri);
240+
const tracker = createTracker(debugType, sessionName, 30000, 'Timed out waiting for debugger event.');
242241
const debugSessionTerminated = createSessionTerminatedPromise(sessionName);
243242

244243
try {
@@ -260,34 +259,37 @@ suite('Run Without Debugging Integration Test', function (): void {
260259

261260
const lastEvent = await tracker.lastEvent;
262261
await debugSessionTerminated;
262+
const actualResultValue = await waitForResultFileValue(resultFilePath, 10000);
263263

264264
assert.strictEqual(lastEvent, 'exited', 'No-debug launch should exit rather than stop on a breakpoint.');
265265
assert.strictEqual(tracker.state.setBreakpointsRequestReceived, false, 'a "no debug" session should not send setBreakpoints requests.');
266266
assert.strictEqual(tracker.state.stoppedEventReceived, false, 'a "no debug" session should not emit stopped events.');
267-
assert.strictEqual(tracker.state.actualExitCode, expectedExitCode, 'Unexpected exit code from run without debugging launch.');
267+
assert.strictEqual(actualResultValue, expectedResultValue, 'Unexpected result value from run without debugging launch.');
268268
} finally {
269269
tracker.dispose();
270270
vscode.debug.removeBreakpoints([breakpoint]);
271+
await util.deleteFile(resultFilePath);
271272
}
272273
});
273274

274275
test('Debug launch should bind and stop at the breakpoint', async () => {
275276
const workspaceFolder = vscode.workspace.workspaceFolders?.[0] ?? assert.fail('No workspace folder available');
276277
const workspacePath = workspaceFolder.uri.fsPath;
277-
const sourceFile = path.join(workspacePath, 'exitCode.cpp');
278+
const sourceFile = path.join(workspacePath, 'debugTest.cpp');
278279
const sourceUri = vscode.Uri.file(sourceFile);
279-
const executableName = isWindows ? 'exitCodeProgram.exe' : 'exitCodeProgram';
280+
const resultFilePath = path.join(workspacePath, 'runWithoutDebuggingResult.txt');
281+
const executableName = isWindows ? 'debugTestProgram.exe' : 'debugTestProgram';
280282
const executablePath = path.join(workspacePath, executableName);
281283
const sessionName = 'Debug Launch Breakpoint Stop';
282284
const debugType = isWindows ? 'cppvsdbg' : 'cppdbg';
283285
const miMode = isMacOS ? 'lldb' : 'gdb';
284286

285287
await compileProgram(workspacePath, sourceFile, executablePath);
286288

287-
const breakpoint = await createBreakpointAtReturnStatement(sourceUri);
289+
const breakpoint = await createBreakpointAtResultWriteStatement(sourceUri);
288290

289291
let launchedSession: vscode.DebugSession | undefined;
290-
const tracker = createTracker(debugType, sessionName, executablePath, 45000, 'Timed out waiting for debugger event in normal debug mode.');
292+
const tracker = createTracker(debugType, sessionName, 45000, 'Timed out waiting for debugger event in normal debug mode.');
291293

292294
const startedSubscription = vscode.debug.onDidStartDebugSession((session) => {
293295
if (session.name === sessionName) {
@@ -331,6 +333,7 @@ suite('Run Without Debugging Integration Test', function (): void {
331333
startedSubscription.dispose();
332334
tracker.dispose();
333335
vscode.debug.removeBreakpoints([breakpoint]);
336+
await util.deleteFile(resultFilePath);
334337
}
335338
});
336339
});

0 commit comments

Comments
 (0)