@@ -25,55 +25,66 @@ class ProcessTests: XCTestCase {
2525
2626 func testBasics( ) throws {
2727 do {
28+ #if os(Windows)
29+ let process = Process ( args: " cmd " , " /c " , " echo " , " hello " )
30+ #else
2831 let process = Process ( args: " echo " , " hello " )
32+ #endif
2933 try process. launch ( )
3034 let result = try process. waitUntilExit ( )
3135 XCTAssertEqual ( try result. utf8Output ( ) , " hello \n " )
3236 XCTAssertEqual ( result. exitStatus, . terminated( code: 0 ) )
3337 XCTAssertEqual ( result. arguments, process. arguments)
3438 }
35-
3639 do {
40+ #if os(Windows)
41+ let process = Process ( args: " cmd.exe " , " /c " , " exit " , " 4 " )
42+ #else
3743 let process = Process ( args: script ( " exit4 " ) )
44+ #endif
3845 try process. launch ( )
3946 let result = try process. waitUntilExit ( )
4047 XCTAssertEqual ( result. exitStatus, . terminated( code: 4 ) )
4148 }
4249 }
4350
4451 func testPopen( ) throws {
45- #if os(Windows)
46- let echo = " echo .exe"
47- #else
48- let echo = " echo "
49- #endif
52+ #if os(Windows)
53+ let echo = [ " cmd .exe" , " /c " , " echo " ]
54+ #else
55+ let echo = [ " echo " ]
56+ #endif
5057 // Test basic echo.
51- XCTAssertEqual ( try Process . popen ( arguments: [ echo, " hello " ] ) . utf8Output ( ) , " hello \n " )
58+ XCTAssertEqual ( try Process . popen ( arguments: echo + [ " hello " ] ) . utf8Output ( ) , " hello \n " )
5259
5360 // Test buffer larger than that allocated.
5461 try withTemporaryFile { file in
5562 let count = 10_000
5663 let stream = BufferedOutputByteStream ( )
5764 stream <<< Format . asRepeating ( string: " a " , count: count)
5865 try localFileSystem. writeFileContents ( file. path, bytes: stream. bytes)
59- #if os(Windows)
60- let cat = " cat .exe"
61- #else
62- let cat = " cat "
63- #endif
64- let outputCount = try Process . popen ( args : cat , file . path . pathString ) . utf8Output ( ) . count
66+ #if os(Windows)
67+ let process = try Process . popen ( args : " cmd .exe" , " /c " , " type " , file . path . pathString )
68+ #else
69+ let process = try Process . popen ( args : " cat " , file . path . pathString )
70+ #endif
71+ let outputCount = try process . utf8Output ( ) . count
6572 XCTAssert ( outputCount == count)
6673 }
6774 }
6875
6976 func testPopenAsync( ) throws {
70- #if os(Windows)
77+ #if os(Windows)
7178 let args = [ " where.exe " , " where " ]
72- let answer = " C: \\ Windows \\ System32 \\ where.exe "
73- #else
79+ var buffer = Array < WCHAR > ( repeating: 0 , count: Int ( MAX_PATH + 1 ) )
80+ guard GetSystemDirectoryW ( & buffer, . init( buffer. count) ) > 0 else {
81+ return XCTFail ( )
82+ }
83+ let answer = String ( decodingCString: buffer, as: UTF16 . self) + " \\ where.exe "
84+ #else
7485 let args = [ " whoami " ]
7586 let answer = NSUserName ( )
76- #endif
87+ #endif
7788 var popenResult : Result < ProcessResult , Error > ?
7889 let group = DispatchGroup ( )
7990 group. enter ( )
@@ -95,25 +106,34 @@ class ProcessTests: XCTestCase {
95106
96107 func testCheckNonZeroExit( ) throws {
97108 do {
109+ #if os(Windows)
110+ let output = try Process . checkNonZeroExit ( args: " cmd.exe " , " /c " , " echo " , " hello " )
111+ #else
98112 let output = try Process . checkNonZeroExit ( args: " echo " , " hello " )
113+ #endif
99114 XCTAssertEqual ( output, " hello \n " )
100115 }
101116
102117 do {
118+ #if os(Windows)
119+ let output = try Process . checkNonZeroExit ( args: " cmd.exe " , " /c " , " exit " , " 4 " )
120+ #else
103121 let output = try Process . checkNonZeroExit ( args: script ( " exit4 " ) )
122+ #endif
104123 XCTFail ( " Unexpected success \( output) " )
105124 } catch ProcessResult . Error . nonZeroExit( let result) {
106125 XCTAssertEqual ( result. exitStatus, . terminated( code: 4 ) )
107126 }
108127 }
109128
110129 func testFindExecutable( ) throws {
130+ #if !os(Windows)
111131 try testWithTemporaryDirectory { tmpdir in
112132 // This process should always work.
113- XCTAssertTrue ( Process . findExecutable ( " ls " ) != nil )
133+ XCTAssertNotNil ( Process . findExecutable ( " ls " ) )
114134
115- XCTAssertEqual ( Process . findExecutable ( " nonExistantProgram " ) , nil )
116- XCTAssertEqual ( Process . findExecutable ( " " ) , nil )
135+ XCTAssertNil ( Process . findExecutable ( " nonExistantProgram " ) )
136+ XCTAssertNil ( Process . findExecutable ( " " ) )
117137
118138 // Create a local nonexecutable file to test.
119139 let tempExecutable = tmpdir. appending ( component: " nonExecutableProgram " )
@@ -124,9 +144,40 @@ class ProcessTests: XCTestCase {
124144 """ )
125145
126146 try withCustomEnv ( [ " PATH " : tmpdir. pathString] ) {
127- XCTAssertEqual ( Process . findExecutable ( " nonExecutableProgram " ) , nil )
147+ XCTAssertNil ( Process . findExecutable ( " nonExecutableProgram " ) )
128148 }
129149 }
150+ #else
151+ try testWithTemporaryDirectory { tmpdir in
152+ // Test System32 without .exe suffix.
153+ XCTAssertNotNil ( Process . findExecutable ( " cmd " ) )
154+
155+ // Test Windows with .exe suffix.
156+ XCTAssertNotNil ( Process . findExecutable ( " explorer.exe " ) )
157+
158+ // Test non-existant programs.
159+ XCTAssertNil ( Process . findExecutable ( " nonExistantProgram " ) )
160+ XCTAssertNil ( Process . findExecutable ( " " ) )
161+
162+ // Copy an executable file to test.
163+ let tempExecutable = tmpdir. appending ( component: " executableProgram.exe " )
164+ try localFileSystem. copy ( from: Process . findExecutable ( " cmd " ) !, to: tempExecutable)
165+
166+ // Create a non-executable file to test.
167+ let tempNonExecutable = tmpdir. appending ( component: " program.bat " )
168+ try localFileSystem. writeFileContents ( tempNonExecutable, bytes: """
169+ @echo off
170+ exit
171+
172+ """ )
173+
174+ try withCustomEnv ( [ " Path " : tmpdir. pathString] ) {
175+ XCTAssertNotNil ( Process . findExecutable ( " executableProgram.exe " ) )
176+ XCTAssertNotNil ( Process . findExecutable ( " executableProgram " ) )
177+ XCTAssertNil ( Process . findExecutable ( " program.bat " ) )
178+ }
179+ }
180+ #endif
130181 }
131182
132183 func testNonExecutableLaunch( ) throws {
@@ -144,7 +195,7 @@ class ProcessTests: XCTestCase {
144195 let process = Process ( args: " nonExecutableProgram " )
145196 try process. launch ( )
146197 XCTFail ( " Should have failed to validate nonExecutableProgram " )
147- } catch Process . Error . missingExecutableProgram ( let program) {
198+ } catch Process . Error . missingExecutableProgram( let program) {
148199 XCTAssert ( program == " nonExecutableProgram " )
149200 }
150201 }
@@ -230,7 +281,11 @@ class ProcessTests: XCTestCase {
230281 #endif
231282
232283 func testThreadSafetyOnWaitUntilExit( ) throws {
284+ #if os(Windows)
285+ let process = Process ( args: " cmd " , " /c " , " echo " , " hello " )
286+ #else
233287 let process = Process ( args: " echo " , " hello " )
288+ #endif
234289 try process. launch ( )
235290
236291 var result1 : String = " "
@@ -255,7 +310,12 @@ class ProcessTests: XCTestCase {
255310
256311 func testStdin( ) throws {
257312 var stdout = [ UInt8] ( )
258- let process = Process ( args: script ( " in-to-out " ) , outputRedirection: . stream( stdout: { stdoutBytes in
313+ #if os(Windows)
314+ let inToOut = [ " python.exe " , script ( " in-to-out " ) ]
315+ #else
316+ let inToOut = [ script ( " in-to-out " ) ]
317+ #endif
318+ let process = Process ( arguments: inToOut, outputRedirection: . stream( stdout: { stdoutBytes in
259319 stdout += stdoutBytes
260320 } , stderr: { _ in } ) )
261321 let stdinStream = try process. launch ( )
@@ -273,14 +333,24 @@ class ProcessTests: XCTestCase {
273333 func testStdoutStdErr( ) throws {
274334 // A simple script to check that stdout and stderr are captured separatly.
275335 do {
276- let result = try Process . popen ( args: script ( " simple-stdout-stderr " ) )
336+ #if os(Windows)
337+ let simpleStdoutStdErr = [ " python.exe " , script ( " simple-stdout-stderr " ) ]
338+ #else
339+ let simpleStdoutStdErr = [ script ( " simple-stdout-stderr " ) ]
340+ #endif
341+ let result = try Process . popen ( arguments: simpleStdoutStdErr)
277342 XCTAssertEqual ( try result. utf8Output ( ) , " simple output \n " )
278343 XCTAssertEqual ( try result. utf8stderrOutput ( ) , " simple error \n " )
279344 }
280345
281346 // A long stdout and stderr output.
282347 do {
283- let result = try Process . popen ( args: script ( " long-stdout-stderr " ) )
348+ #if os(Windows)
349+ let longStdoutStdErr = [ " python.exe " , script ( " long-stdout-stderr " ) ]
350+ #else
351+ let longStdoutStdErr = [ script ( " long-stdout-stderr " ) ]
352+ #endif
353+ let result = try Process . popen ( arguments: longStdoutStdErr)
284354 let count = 16 * 1024
285355 XCTAssertEqual ( try result. utf8Output ( ) , String ( repeating: " 1 " , count: count) )
286356 XCTAssertEqual ( try result. utf8stderrOutput ( ) , String ( repeating: " 2 " , count: count) )
@@ -298,7 +368,12 @@ class ProcessTests: XCTestCase {
298368 func testStdoutStdErrRedirected( ) throws {
299369 // A simple script to check that stdout and stderr are captured in the same location.
300370 do {
301- let process = Process ( args: script ( " simple-stdout-stderr " ) , outputRedirection: . collect( redirectStderr: true ) )
371+ #if os(Windows)
372+ let simpleStdoutStdErr = [ " python.exe " , script ( " simple-stdout-stderr " ) ]
373+ #else
374+ let simpleStdoutStdErr = [ script ( " simple-stdout-stderr " ) ]
375+ #endif
376+ let process = Process ( arguments: simpleStdoutStdErr, outputRedirection: . collect( redirectStderr: true ) )
302377 try process. launch ( )
303378 let result = try process. waitUntilExit ( )
304379 XCTAssertEqual ( try result. utf8Output ( ) , " simple error \n simple output \n " )
@@ -307,7 +382,12 @@ class ProcessTests: XCTestCase {
307382
308383 // A long stdout and stderr output.
309384 do {
310- let process = Process ( args: script ( " long-stdout-stderr " ) , outputRedirection: . collect( redirectStderr: true ) )
385+ #if os(Windows)
386+ let longStdoutStdErr = [ " python.exe " , script ( " long-stdout-stderr " ) ]
387+ #else
388+ let longStdoutStdErr = [ script ( " long-stdout-stderr " ) ]
389+ #endif
390+ let process = Process ( arguments: longStdoutStdErr, outputRedirection: . collect( redirectStderr: true ) )
311391 try process. launch ( )
312392 let result = try process. waitUntilExit ( )
313393
@@ -320,7 +400,12 @@ class ProcessTests: XCTestCase {
320400 func testStdoutStdErrStreaming( ) throws {
321401 var stdout = [ UInt8] ( )
322402 var stderr = [ UInt8] ( )
323- let process = Process ( args: script ( " long-stdout-stderr " ) , outputRedirection: . stream( stdout: { stdoutBytes in
403+ #if os(Windows)
404+ let longStdoutStdErr = [ " python.exe " , script ( " long-stdout-stderr " ) ]
405+ #else
406+ let longStdoutStdErr = [ script ( " long-stdout-stderr " ) ]
407+ #endif
408+ let process = Process ( arguments: longStdoutStdErr, outputRedirection: . stream( stdout: { stdoutBytes in
324409 stdout += stdoutBytes
325410 } , stderr: { stderrBytes in
326411 stderr += stderrBytes
@@ -336,7 +421,12 @@ class ProcessTests: XCTestCase {
336421 func testStdoutStdErrStreamingRedirected( ) throws {
337422 var stdout = [ UInt8] ( )
338423 var stderr = [ UInt8] ( )
339- let process = Process ( args: script ( " long-stdout-stderr " ) , outputRedirection: . stream( stdout: { stdoutBytes in
424+ #if os(Windows)
425+ let longStdoutStdErr = [ " python.exe " , script ( " long-stdout-stderr " ) ]
426+ #else
427+ let longStdoutStdErr = [ script ( " long-stdout-stderr " ) ]
428+ #endif
429+ let process = Process ( arguments: longStdoutStdErr, outputRedirection: . stream( stdout: { stdoutBytes in
340430 stdout += stdoutBytes
341431 } , stderr: { stderrBytes in
342432 stderr += stderrBytes
@@ -370,15 +460,21 @@ class ProcessTests: XCTestCase {
370460 try localFileSystem. createDirectory ( childPath. parentDirectory, recursive: true )
371461 try localFileSystem. writeFileContents ( childPath, bytes: ByteString ( " child " ) )
372462
463+ #if os(Windows)
464+ let args = [ " cmd.exe " , " /c " , " type " , " file " ]
465+ #else
466+ let args = [ " cat " , " file " ]
467+ #endif
468+
373469 do {
374- let process = Process ( arguments: [ " cat " , " file " ] , workingDirectory: tempDirPath)
470+ let process = Process ( arguments: args , workingDirectory: tempDirPath)
375471 try process. launch ( )
376472 let result = try process. waitUntilExit ( )
377473 XCTAssertEqual ( try result. utf8Output ( ) , " parent " )
378474 }
379475
380476 do {
381- let process = Process ( arguments: [ " cat " , " file " ] , workingDirectory: childPath. parentDirectory)
477+ let process = Process ( arguments: args , workingDirectory: childPath. parentDirectory)
382478 try process. launch ( )
383479 let result = try process. waitUntilExit ( )
384480 XCTAssertEqual ( try result. utf8Output ( ) , " child " )
0 commit comments