@@ -2,12 +2,21 @@ import * as assert from 'assert';
22import * as sinon from 'sinon' ;
33import { Disposable , Terminal , TerminalShellExecution , TerminalShellExecutionEndEvent } from 'vscode' ;
44import * as windowApis from '../../../common/window.apis' ;
5+ import { ShellConstants } from '../../../features/common/shellConstants' ;
56import * as shellDetector from '../../../features/common/shellDetector' ;
67import { runInTerminal } from '../../../features/terminal/runInTerminal' ;
78import * as terminalUtils from '../../../features/terminal/utils' ;
89import { createMockPythonEnvironment } from '../../mocks/pythonEnvironment' ;
910
1011suite ( 'runInTerminal' , ( ) => {
12+ const posixShells = [
13+ ShellConstants . SH ,
14+ ShellConstants . BASH ,
15+ ShellConstants . ZSH ,
16+ ShellConstants . KSH ,
17+ ShellConstants . GITBASH ,
18+ ] ;
19+
1120 teardown ( ( ) => {
1221 sinon . restore ( ) ;
1322 } ) ;
@@ -50,7 +59,7 @@ suite('runInTerminal', () => {
5059 await new Promise < void > ( ( resolve ) => setImmediate ( resolve ) ) ;
5160
5261 sinon . assert . notCalled ( terminal . sendText as sinon . SinonStub ) ;
53- sinon . assert . calledOnce ( shellIntegration . executeCommand ) ;
62+ sinon . assert . calledOnceWithExactly ( shellIntegration . executeCommand , 'python' , [ 'main.py' ] ) ;
5463 assert . ok ( endListener , 'shell execution end listener should be registered' ) ;
5564
5665 endListener ! ( { terminal, execution } as unknown as TerminalShellExecutionEndEvent ) ;
@@ -74,8 +83,8 @@ suite('runInTerminal', () => {
7483 sinon . assert . calledOnceWithExactly ( sendText , 'python main.py\n' ) ;
7584 } ) ;
7685
77- test ( 'preserves special characters in zsh script paths with shell integration' , async ( ) => {
78- sinon . stub ( shellDetector , 'identifyTerminalShell' ) . returns ( 'zsh ') ;
86+ test ( 'preserves special characters in POSIX shell arguments with shell integration' , async ( ) => {
87+ const identifyTerminalShellStub = sinon . stub ( shellDetector , 'identifyTerminalShell' ) ;
7988 const execution = { } as TerminalShellExecution ;
8089 const executeCommand = sinon . stub ( ) . returns ( execution ) ;
8190 const terminal = {
@@ -98,48 +107,49 @@ suite('runInTerminal', () => {
98107 [ '/workspace/$(touch marker).py' , "python '/workspace/$(touch marker).py'" ] ,
99108 ] ;
100109
101- for ( const [ script , command ] of cases ) {
102- const runPromise = runInTerminal ( environment , terminal , { cwd : '/workspace' , args : [ script ] } ) ;
103- await new Promise < void > ( ( resolve ) => setImmediate ( resolve ) ) ;
104- sinon . assert . calledWithExactly ( executeCommand , command ) ;
105- assert . ok ( endListener , 'shell execution end listener should be registered' ) ;
106- endListener ! ( { terminal, execution } as unknown as TerminalShellExecutionEndEvent ) ;
107- await runPromise ;
110+ let callIndex = 0 ;
111+ for ( const shell of posixShells ) {
112+ identifyTerminalShellStub . returns ( shell ) ;
113+ for ( const [ script , command ] of cases ) {
114+ const runPromise = runInTerminal ( environment , terminal , { cwd : '/workspace' , args : [ script ] } ) ;
115+ await new Promise < void > ( ( resolve ) => setImmediate ( resolve ) ) ;
116+ assert . deepStrictEqual ( executeCommand . getCall ( callIndex ) . args , [ command ] ) ;
117+ assert . ok ( endListener , 'shell execution end listener should be registered' ) ;
118+ endListener ! ( { terminal, execution } as unknown as TerminalShellExecutionEndEvent ) ;
119+ await runPromise ;
120+ callIndex += 1 ;
121+ }
108122 }
123+ sinon . assert . callCount ( executeCommand , posixShells . length * cases . length ) ;
109124 } ) ;
110125
111- test ( 'preserves special characters in zsh script paths without shell integration' , async ( ) => {
112- sinon . stub ( shellDetector , 'identifyTerminalShell' ) . returns ( 'zsh ') ;
126+ test ( 'preserves special characters in POSIX shell arguments without shell integration' , async ( ) => {
127+ const identifyTerminalShellStub = sinon . stub ( shellDetector , 'identifyTerminalShell' ) ;
113128 sinon . stub ( terminalUtils , 'waitForShellIntegration' ) . resolves ( false ) ;
114129 const sendText = sinon . stub ( ) ;
115- const terminal = {
116- name : 'Python' ,
117- shellIntegration : undefined ,
118- sendText,
119- } as unknown as Terminal ;
120130 const environment = createMockPythonEnvironment ( { envPath : '/env/bin/python' } ) ;
131+ const cases = [
132+ [ '/workspace/cost$AUDIT_UNSET.py' , 'python /workspace/cost\\$AUDIT_UNSET.py\n' ] ,
133+ [ "/workspace/it's_python.py" , 'python "/workspace/it\'s_python.py"\n' ] ,
134+ [ '=report.py' , 'python \\=report.py\n' ] ,
135+ [ '/workspace/$(touch marker).py' , "python '/workspace/$(touch marker).py'\n" ] ,
136+ ] ;
121137
122- await runInTerminal ( environment , terminal , {
123- cwd : '/workspace' ,
124- args : [ '/workspace/cost$AUDIT_UNSET.py' ] ,
125- } ) ;
126- await runInTerminal ( environment , terminal , {
127- cwd : '/workspace' ,
128- args : [ "/workspace/it's_python.py" ] ,
129- } ) ;
130- await runInTerminal ( environment , terminal , {
131- cwd : '/workspace' ,
132- args : [ '=report.py' ] ,
133- } ) ;
134- await runInTerminal ( environment , terminal , {
135- cwd : '/workspace' ,
136- args : [ '/workspace/$(touch marker).py' ] ,
137- } ) ;
138-
139- sinon . assert . calledWithExactly ( sendText , 'python /workspace/cost\\$AUDIT_UNSET.py\n' ) ;
140- sinon . assert . calledWithExactly ( sendText , 'python "/workspace/it\'s_python.py"\n' ) ;
141- sinon . assert . calledWithExactly ( sendText , 'python \\=report.py\n' ) ;
142- sinon . assert . calledWithExactly ( sendText , "python '/workspace/$(touch marker).py'\n" ) ;
138+ let callIndex = 0 ;
139+ for ( const shell of posixShells ) {
140+ identifyTerminalShellStub . returns ( shell ) ;
141+ const terminal = {
142+ name : 'Python' ,
143+ shellIntegration : undefined ,
144+ sendText,
145+ } as unknown as Terminal ;
146+ for ( const [ script , command ] of cases ) {
147+ await runInTerminal ( environment , terminal , { cwd : '/workspace' , args : [ script ] } ) ;
148+ assert . deepStrictEqual ( sendText . getCall ( callIndex ) . args , [ command ] ) ;
149+ callIndex += 1 ;
150+ }
151+ }
152+ sinon . assert . callCount ( sendText , posixShells . length * cases . length ) ;
143153 } ) ;
144154
145155 test ( 'does not wait again when reusing a terminal without shell integration' , async ( ) => {
0 commit comments