From 886d87b13fbca33002d14a987e6601b5fff17a24 Mon Sep 17 00:00:00 2001 From: Wasim Date: Fri, 6 Nov 2026 00:52:46 +0530 Subject: [PATCH] Do not add redundant quotes to script path in executeUsingExtension (#26274) --- .../codeExecution/codeExecutionManager.ts | 2 +- .../codeExecutionManager.unit.test.ts | 74 ++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/client/terminals/codeExecution/codeExecutionManager.ts b/src/client/terminals/codeExecution/codeExecutionManager.ts index 48165adcd169..fe1520a2f61e 100644 --- a/src/client/terminals/codeExecution/codeExecutionManager.ts +++ b/src/client/terminals/codeExecution/codeExecutionManager.ts @@ -142,7 +142,7 @@ export class CodeExecutionManager implements ICodeExecutionManager { // Check on setting terminal.launchArgs const launchArgs = pythonSettings.terminal.launchArgs; - const totalArgs = [...launchArgs, fileToExecute.fsPath.fileToCommandArgumentForPythonExt()]; + const totalArgs = [...launchArgs, fileToExecute.fsPath]; const show = this.shouldTerminalFocusOnStart(fileToExecute); let terminal: Terminal | undefined; diff --git a/src/test/terminals/codeExecution/codeExecutionManager.unit.test.ts b/src/test/terminals/codeExecution/codeExecutionManager.unit.test.ts index 726b118ce180..90a78a9925d6 100644 --- a/src/test/terminals/codeExecution/codeExecutionManager.unit.test.ts +++ b/src/test/terminals/codeExecution/codeExecutionManager.unit.test.ts @@ -10,7 +10,7 @@ import { Commands } from '../../../client/common/constants'; import { IServiceContainer } from '../../../client/ioc/types'; import { CodeExecutionManager } from '../../../client/terminals/codeExecution/codeExecutionManager'; import { ICodeExecutionHelper, ICodeExecutionManager, ICodeExecutionService } from '../../../client/terminals/types'; -import { IConfigurationService } from '../../../client/common/types'; +import { IConfigurationService, IPythonSettings } from '../../../client/common/types'; import { IInterpreterService } from '../../../client/interpreter/contracts'; import { PythonEnvironment } from '../../../client/pythonEnvironments/info'; import * as triggerApis from '../../../client/pythonEnvironments/creation/createEnvironmentTrigger'; @@ -185,6 +185,78 @@ suite('Terminal - Code Execution Manager', () => { ); }); + test('Ensure executeUsingExtension does not pass extra quotes in path with spaces', async () => { + useEnvExtensionStub.returns(true); + const runInTerminalStub = sinon.stub(extapi, 'runInTerminal'); + const showStub = sinon.stub(); + runInTerminalStub.resolves({ show: showStub } as any); + + let commandHandler: undefined | ((file: Uri) => Promise); + commandManager + .setup((c) => c.registerCommand as any) + .returns(() => { + return (command: string, callback: (...args: any[]) => any, _thisArg?: any) => { + if (command === Commands.Exec_In_Terminal) { + commandHandler = callback; + } + return { dispose: () => void 0 }; + }; + }); + + const pythonSettings = TypeMoq.Mock.ofType(); + pythonSettings.setup((p) => p.terminal).returns(() => ({ launchArgs: ['--custom'], executeInFileDir: false } as any)); + configService.setup((c) => c.getSettings(TypeMoq.It.isAny())).returns(() => pythonSettings.object); + + const helper = TypeMoq.Mock.ofType(); + helper.setup((h) => h.saveFileIfDirty(TypeMoq.It.isAny())).returns((f) => Promise.resolve(f)); + serviceContainer.setup((s) => s.get(TypeMoq.It.isValue(ICodeExecutionHelper))).returns(() => helper.object); + + executionManager.registerCommands(); + + const fileWithSpaces = Uri.file('/path with spaces/script.py'); + await commandHandler!(fileWithSpaces); + + expect(runInTerminalStub.calledOnce).to.be.true; + const passedArgs = runInTerminalStub.firstCall.args[1]; + expect(passedArgs).to.deep.equal(['--custom', fileWithSpaces.fsPath]); + }); + + test('Ensure executeUsingExtension does not pass extra quotes in path with spaces for dedicated terminal', async () => { + useEnvExtensionStub.returns(true); + const runInDedicatedTerminalStub = sinon.stub(extapi, 'runInDedicatedTerminal'); + const showStub = sinon.stub(); + runInDedicatedTerminalStub.resolves({ show: showStub } as any); + + let commandHandler: undefined | ((file: Uri) => Promise); + commandManager + .setup((c) => c.registerCommand as any) + .returns(() => { + return (command: string, callback: (...args: any[]) => any, _thisArg?: any) => { + if (command === Commands.Exec_In_Separate_Terminal) { + commandHandler = callback; + } + return { dispose: () => void 0 }; + }; + }); + + const pythonSettings = TypeMoq.Mock.ofType(); + pythonSettings.setup((p) => p.terminal).returns(() => ({ launchArgs: [], executeInFileDir: false } as any)); + configService.setup((c) => c.getSettings(TypeMoq.It.isAny())).returns(() => pythonSettings.object); + + const helper = TypeMoq.Mock.ofType(); + helper.setup((h) => h.saveFileIfDirty(TypeMoq.It.isAny())).returns((f) => Promise.resolve(f)); + serviceContainer.setup((s) => s.get(TypeMoq.It.isValue(ICodeExecutionHelper))).returns(() => helper.object); + + executionManager.registerCommands(); + + const fileWithSpaces = Uri.file('C:\\My Folder with Spaces\\main.py'); + await commandHandler!(fileWithSpaces); + + expect(runInDedicatedTerminalStub.calledOnce).to.be.true; + const passedArgs = runInDedicatedTerminalStub.firstCall.args[1]; + expect(passedArgs).to.deep.equal([fileWithSpaces.fsPath]); + }); + async function testExecutionOfSelectionWithoutAnyActiveDocument(commandId: string, executionSericeId: string) { let commandHandler: undefined | (() => Promise); commandManager