Skip to content

Commit 8f521a0

Browse files
committed
Fix ProcessTests on Windows
1 parent dab60f0 commit 8f521a0

File tree

2 files changed

+129
-33
lines changed

2 files changed

+129
-33
lines changed

Tests/TSCBasicTests/ProcessTests.swift

Lines changed: 127 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -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\nsimple 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")

Tests/TSCBasicTests/TemporaryFileTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,18 +138,18 @@ class TemporaryFileTests: XCTestCase {
138138
}
139139

140140
/// Check that the temporary file doesn't leak file descriptors.
141+
#if !os(Windows) // `fileDescriptor` is currently unavailable in Windows
141142
func testLeaks() throws {
142143
// We check this by testing that we get back the same FD after a
143144
// sequence of creating and destroying TemporaryFile objects. I don't
144145
// believe that this is guaranteed by POSIX, but it is true on all
145146
// platforms I know of.
146-
#if !os(Windows)
147147
let initialFD = try Int(withTemporaryFile { return $0.fileHandle.fileDescriptor })
148148
for _ in 0..<10 {
149149
_ = try withTemporaryFile { return $0.fileHandle }
150150
}
151151
let endFD = try Int(withTemporaryFile { return $0.fileHandle.fileDescriptor })
152152
XCTAssertEqual(initialFD, endFD)
153-
#endif
154153
}
154+
#endif
155155
}

0 commit comments

Comments
 (0)