@@ -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 )
@@ -986,44 +988,49 @@ extension SubprocessIntegrationTests {
986988 #expect( output == expected)
987989 }
988990
991+ #if compiler(>=6.2)
989992 @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- }
993+ // Use an exit test to isolate the test runner process from our deliberate attempt to double-close a file descriptor
994+ await #expect( processExitsWith: . success, performing: {
995+ #if os(Windows)
996+ let setup = TestSetup (
997+ executable: . name( " cmd.exe " ) ,
998+ arguments: [ " /c " , " echo Hello World " ]
999+ )
1000+ #else
1001+ let setup = TestSetup (
1002+ executable: . path( " /bin/sh " ) ,
1003+ arguments: [ " -c " , " echo Hello World " ]
1004+ )
1005+ #endif
1006+ let outputFilePath = FilePath ( FileManager . default. temporaryDirectory. _fileSystemPath)
1007+ . appending ( " Test.out " )
1008+ if FileManager . default. fileExists ( atPath: outputFilePath. string) {
1009+ try FileManager . default. removeItem ( atPath: outputFilePath. string)
1010+ }
1011+ let outputFile : FileDescriptor = try . open(
1012+ outputFilePath,
1013+ . readWrite,
1014+ options: . create,
1015+ permissions: [ . ownerReadWrite, . groupReadWrite]
1016+ )
1017+ let echoResult = try await _run (
1018+ setup,
1019+ input: . none,
1020+ output: . fileDescriptor(
1021+ outputFile,
1022+ closeAfterSpawningProcess: true
1023+ ) ,
1024+ error: . discarded
1025+ )
1026+ #expect( echoResult. terminationStatus. isSuccess)
1027+ // Make sure the file descriptor is already closed
1028+ #expect( throws: Errno . badFileDescriptor) {
1029+ try outputFile. close ( )
1030+ }
1031+ } )
10261032 }
1033+ #endif
10271034
10281035 #if SubprocessFoundation
10291036 @Test func testDataOutput( ) async throws {
@@ -1242,17 +1249,19 @@ extension SubprocessIntegrationTests {
12421249 options: . create,
12431250 permissions: [ . ownerReadWrite, . groupReadWrite]
12441251 )
1245- let echoResult = try await _run (
1246- setup,
1247- input: . none,
1248- output: . discarded,
1249- error: . fileDescriptor(
1250- outputFile,
1251- closeAfterSpawningProcess: false
1252+ let echoResult = try await outputFile. closeAfter {
1253+ let echoResult = try await _run (
1254+ setup,
1255+ input: . none,
1256+ output: . discarded,
1257+ error: . fileDescriptor(
1258+ outputFile,
1259+ closeAfterSpawningProcess: false
1260+ )
12521261 )
1253- )
1254- #expect ( echoResult. terminationStatus . isSuccess )
1255- try outputFile . close ( )
1262+ #expect ( echoResult . terminationStatus . isSuccess )
1263+ return echoResult
1264+ }
12561265 let outputData : Data = try Data (
12571266 contentsOf: URL ( filePath: outputFilePath. string)
12581267 )
@@ -1263,44 +1272,49 @@ extension SubprocessIntegrationTests {
12631272 #expect( output == expected)
12641273 }
12651274
1275+ #if compiler(>=6.2)
12661276 @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
1277+ // Use an exit test to isolate the test runner process from our deliberate attempt to double-close a file descriptor
1278+ await #expect( processExitsWith: . success, performing: {
1279+ #if os(Windows)
1280+ let setup = TestSetup (
1281+ executable: . name( " cmd.exe " ) ,
1282+ arguments: [ " /c " , " echo Hello World " , " 1>&2 " ]
12961283 )
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- }
1284+ #else
1285+ let setup = TestSetup (
1286+ executable: . path( " /bin/sh " ) ,
1287+ arguments: [ " -c " , " echo Hello World " , " 1>&2 " ]
1288+ )
1289+ #endif
1290+ let outputFilePath = FilePath ( FileManager . default. temporaryDirectory. _fileSystemPath)
1291+ . appending ( " TestError.out " )
1292+ if FileManager . default. fileExists ( atPath: outputFilePath. string) {
1293+ try FileManager . default. removeItem ( atPath: outputFilePath. string)
1294+ }
1295+ let outputFile : FileDescriptor = try . open(
1296+ outputFilePath,
1297+ . readWrite,
1298+ options: . create,
1299+ permissions: [ . ownerReadWrite, . groupReadWrite]
1300+ )
1301+ let echoResult = try await _run (
1302+ setup,
1303+ input: . none,
1304+ output: . discarded,
1305+ error: . fileDescriptor(
1306+ outputFile,
1307+ closeAfterSpawningProcess: true
1308+ )
1309+ )
1310+ #expect( echoResult. terminationStatus. isSuccess)
1311+ // Make sure the file descriptor is already closed
1312+ #expect( throws: Errno . badFileDescriptor) {
1313+ try outputFile. close ( )
1314+ }
1315+ } )
13031316 }
1317+ #endif
13041318
13051319 @Test func testFileDescriptorOutputErrorToSameFile( ) async throws {
13061320 #if os(Windows)
@@ -1326,20 +1340,22 @@ extension SubprocessIntegrationTests {
13261340 options: . create,
13271341 permissions: [ . ownerReadWrite, . groupReadWrite]
13281342 )
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
1343+ let echoResult = try await outputFile. closeAfter {
1344+ let echoResult = try await _run (
1345+ setup,
1346+ input: . none,
1347+ output: . fileDescriptor(
1348+ outputFile,
1349+ closeAfterSpawningProcess: false
1350+ ) ,
1351+ error: . fileDescriptor(
1352+ outputFile,
1353+ closeAfterSpawningProcess: false
1354+ )
13391355 )
1340- )
1341- #expect ( echoResult. terminationStatus . isSuccess )
1342- try outputFile . close ( )
1356+ #expect ( echoResult . terminationStatus . isSuccess )
1357+ return echoResult
1358+ }
13431359 let outputData : Data = try Data (
13441360 contentsOf: URL ( filePath: outputFilePath. string)
13451361 )
0 commit comments