@@ -965,17 +965,19 @@ extension SubprocessIntegrationTests {
965965 options: . create,
966966 permissions: [ . ownerReadWrite, . groupReadWrite]
967967 )
968- let echoResult = try await _run (
969- setup,
970- input: . none,
971- output: . fileDescriptor(
972- outputFile,
973- closeAfterSpawningProcess: false
974- ) ,
975- error: . discarded
976- )
977- #expect( echoResult. terminationStatus. isSuccess)
978- try outputFile. close ( )
968+ let echoResult = try await outputFile. closeAfter {
969+ let echoResult = try await _run (
970+ setup,
971+ input: . none,
972+ output: . fileDescriptor(
973+ outputFile,
974+ closeAfterSpawningProcess: false
975+ ) ,
976+ error: . discarded
977+ )
978+ #expect( echoResult. terminationStatus. isSuccess)
979+ return echoResult
980+ }
979981 let outputData : Data = try Data (
980982 contentsOf: URL ( filePath: outputFilePath. string)
981983 )
@@ -987,42 +989,45 @@ extension SubprocessIntegrationTests {
987989 }
988990
989991 @Test func testFileDescriptorOutputAutoClose( ) async throws {
990- #if os(Windows)
991- let setup = TestSetup (
992- executable: . name( " cmd.exe " ) ,
993- arguments: [ " /c " , " echo Hello World " ]
994- )
995- #else
996- let setup = TestSetup (
997- executable: . path( " /bin/sh " ) ,
998- arguments: [ " -c " , " echo Hello World " ]
999- )
1000- #endif
1001- let outputFilePath = FilePath ( FileManager . default. temporaryDirectory. _fileSystemPath)
1002- . appending ( " Test.out " )
1003- if FileManager . default. fileExists ( atPath: outputFilePath. string) {
1004- try FileManager . default. removeItem ( atPath: outputFilePath. string)
1005- }
1006- let outputFile : FileDescriptor = try . open(
1007- outputFilePath,
1008- . readWrite,
1009- options: . create,
1010- permissions: [ . ownerReadWrite, . groupReadWrite]
1011- )
1012- let echoResult = try await _run (
1013- setup,
1014- input: . none,
1015- output: . fileDescriptor(
1016- outputFile,
1017- closeAfterSpawningProcess: true
1018- ) ,
1019- error: . discarded
1020- )
1021- #expect( echoResult. terminationStatus. isSuccess)
1022- // Make sure the file descriptor is already closed
1023- #expect( throws: Errno . badFileDescriptor) {
1024- try outputFile. close ( )
1025- }
992+ // Use an exit test to isolate the test runner process from our deliberate attempt to double-close a file descriptor
993+ await #expect( processExitsWith: . success, performing: {
994+ #if os(Windows)
995+ let setup = TestSetup (
996+ executable: . name( " cmd.exe " ) ,
997+ arguments: [ " /c " , " echo Hello World " ]
998+ )
999+ #else
1000+ let setup = TestSetup (
1001+ executable: . path( " /bin/sh " ) ,
1002+ arguments: [ " -c " , " echo Hello World " ]
1003+ )
1004+ #endif
1005+ let outputFilePath = FilePath ( FileManager . default. temporaryDirectory. _fileSystemPath)
1006+ . appending ( " Test.out " )
1007+ if FileManager . default. fileExists ( atPath: outputFilePath. string) {
1008+ try FileManager . default. removeItem ( atPath: outputFilePath. string)
1009+ }
1010+ let outputFile : FileDescriptor = try . open(
1011+ outputFilePath,
1012+ . readWrite,
1013+ options: . create,
1014+ permissions: [ . ownerReadWrite, . groupReadWrite]
1015+ )
1016+ let echoResult = try await _run (
1017+ setup,
1018+ input: . none,
1019+ output: . fileDescriptor(
1020+ outputFile,
1021+ closeAfterSpawningProcess: true
1022+ ) ,
1023+ error: . discarded
1024+ )
1025+ #expect( echoResult. terminationStatus. isSuccess)
1026+ // Make sure the file descriptor is already closed
1027+ #expect( throws: Errno . badFileDescriptor) {
1028+ try outputFile. close ( )
1029+ }
1030+ } )
10261031 }
10271032
10281033 #if SubprocessFoundation
@@ -1242,17 +1247,19 @@ extension SubprocessIntegrationTests {
12421247 options: . create,
12431248 permissions: [ . ownerReadWrite, . groupReadWrite]
12441249 )
1245- let echoResult = try await _run (
1246- setup,
1247- input: . none,
1248- output: . discarded,
1249- error: . fileDescriptor(
1250- outputFile,
1251- closeAfterSpawningProcess: false
1250+ let echoResult = try await outputFile. closeAfter {
1251+ let echoResult = try await _run (
1252+ setup,
1253+ input: . none,
1254+ output: . discarded,
1255+ error: . fileDescriptor(
1256+ outputFile,
1257+ closeAfterSpawningProcess: false
1258+ )
12521259 )
1253- )
1254- #expect ( echoResult. terminationStatus . isSuccess )
1255- try outputFile . close ( )
1260+ #expect ( echoResult . terminationStatus . isSuccess )
1261+ return echoResult
1262+ }
12561263 let outputData : Data = try Data (
12571264 contentsOf: URL ( filePath: outputFilePath. string)
12581265 )
@@ -1263,44 +1270,49 @@ extension SubprocessIntegrationTests {
12631270 #expect( output == expected)
12641271 }
12651272
1273+ #if compiler(>=6.2)
12661274 @Test func testFileDescriptorErrorOutputAutoClose( ) async throws {
1267- #if os(Windows)
1268- let setup = TestSetup (
1269- executable: . name( " cmd.exe " ) ,
1270- arguments: [ " /c " , " echo Hello World " , " 1>&2 " ]
1271- )
1272- #else
1273- let setup = TestSetup (
1274- executable: . path( " /bin/sh " ) ,
1275- arguments: [ " -c " , " echo Hello World " , " 1>&2 " ]
1276- )
1277- #endif
1278- let outputFilePath = FilePath ( FileManager . default. temporaryDirectory. _fileSystemPath)
1279- . appending ( " TestError.out " )
1280- if FileManager . default. fileExists ( atPath: outputFilePath. string) {
1281- try FileManager . default. removeItem ( atPath: outputFilePath. string)
1282- }
1283- let outputFile : FileDescriptor = try . open(
1284- outputFilePath,
1285- . readWrite,
1286- options: . create,
1287- permissions: [ . ownerReadWrite, . groupReadWrite]
1288- )
1289- let echoResult = try await _run (
1290- setup,
1291- input: . none,
1292- output: . discarded,
1293- error: . fileDescriptor(
1294- outputFile,
1295- closeAfterSpawningProcess: true
1275+ // Use an exit test to isolate the test runner process from our deliberate attempt to double-close a file descriptor
1276+ await #expect( processExitsWith: . success, performing: {
1277+ #if os(Windows)
1278+ let setup = TestSetup (
1279+ executable: . name( " cmd.exe " ) ,
1280+ arguments: [ " /c " , " echo Hello World " , " 1>&2 " ]
12961281 )
1297- )
1298- #expect( echoResult. terminationStatus. isSuccess)
1299- // Make sure the file descriptor is already closed
1300- #expect( throws: Errno . badFileDescriptor) {
1301- try outputFile. close ( )
1302- }
1282+ #else
1283+ let setup = TestSetup (
1284+ executable: . path( " /bin/sh " ) ,
1285+ arguments: [ " -c " , " echo Hello World " , " 1>&2 " ]
1286+ )
1287+ #endif
1288+ let outputFilePath = FilePath ( FileManager . default. temporaryDirectory. _fileSystemPath)
1289+ . appending ( " TestError.out " )
1290+ if FileManager . default. fileExists ( atPath: outputFilePath. string) {
1291+ try FileManager . default. removeItem ( atPath: outputFilePath. string)
1292+ }
1293+ let outputFile : FileDescriptor = try . open(
1294+ outputFilePath,
1295+ . readWrite,
1296+ options: . create,
1297+ permissions: [ . ownerReadWrite, . groupReadWrite]
1298+ )
1299+ let echoResult = try await _run (
1300+ setup,
1301+ input: . none,
1302+ output: . discarded,
1303+ error: . fileDescriptor(
1304+ outputFile,
1305+ closeAfterSpawningProcess: true
1306+ )
1307+ )
1308+ #expect( echoResult. terminationStatus. isSuccess)
1309+ // Make sure the file descriptor is already closed
1310+ #expect( throws: Errno . badFileDescriptor) {
1311+ try outputFile. close ( )
1312+ }
1313+ } )
13031314 }
1315+ #endif
13041316
13051317 @Test func testFileDescriptorOutputErrorToSameFile( ) async throws {
13061318 #if os(Windows)
@@ -1326,20 +1338,22 @@ extension SubprocessIntegrationTests {
13261338 options: . create,
13271339 permissions: [ . ownerReadWrite, . groupReadWrite]
13281340 )
1329- let echoResult = try await _run (
1330- setup,
1331- input: . none,
1332- output: . fileDescriptor(
1333- outputFile,
1334- closeAfterSpawningProcess: false
1335- ) ,
1336- error: . fileDescriptor(
1337- outputFile,
1338- closeAfterSpawningProcess: false
1341+ let echoResult = try await outputFile. closeAfter {
1342+ let echoResult = try await _run (
1343+ setup,
1344+ input: . none,
1345+ output: . fileDescriptor(
1346+ outputFile,
1347+ closeAfterSpawningProcess: false
1348+ ) ,
1349+ error: . fileDescriptor(
1350+ outputFile,
1351+ closeAfterSpawningProcess: false
1352+ )
13391353 )
1340- )
1341- #expect ( echoResult. terminationStatus . isSuccess )
1342- try outputFile . close ( )
1354+ #expect ( echoResult . terminationStatus . isSuccess )
1355+ return echoResult
1356+ }
13431357 let outputData : Data = try Data (
13441358 contentsOf: URL ( filePath: outputFilePath. string)
13451359 )
0 commit comments