diff --git a/Sources/Foundation/FileManager+Win32.swift b/Sources/Foundation/FileManager+Win32.swift index 9069aa1925..4f46a2f847 100644 --- a/Sources/Foundation/FileManager+Win32.swift +++ b/Sources/Foundation/FileManager+Win32.swift @@ -709,9 +709,10 @@ extension FileManager { } internal func _isExecutableFile(atPath path: String) -> Bool { - var isDirectory: ObjCBool = false - guard fileExists(atPath: path, isDirectory: &isDirectory) else { return false } - return !isDirectory.boolValue && _isReadableFile(atPath: path) + var binaryType = DWORD(0) + return path.withCString(encodedAs: UTF16.self) { + GetBinaryTypeW($0, &binaryType) + } } internal func _isDeletableFile(atPath path: String) -> Bool { diff --git a/Tests/Foundation/Tests/TestFileManager.swift b/Tests/Foundation/Tests/TestFileManager.swift index b1b0208e61..c8d50061c9 100644 --- a/Tests/Foundation/Tests/TestFileManager.swift +++ b/Tests/Foundation/Tests/TestFileManager.swift @@ -265,8 +265,10 @@ class TestFileManager : XCTestCase { func test_isExecutableFile() { let fm = FileManager.default let path = NSTemporaryDirectory() + "test_isExecutableFile\(NSUUID().uuidString)" + let exePath = path + ".exe" defer { try? fm.removeItem(atPath: path) + try? fm.removeItem(atPath: exePath) } do { @@ -275,16 +277,21 @@ class TestFileManager : XCTestCase { // test unExecutable if file has no permissions try fm.setAttributes([.posixPermissions : NSNumber(value: Int16(0o0000))], ofItemAtPath: path) -#if os(Windows) - // Files are always executable on Windows - XCTAssertTrue(fm.isExecutableFile(atPath: path)) -#else XCTAssertFalse(fm.isExecutableFile(atPath: path)) -#endif +#if os(Windows) + // test unExecutable even if file has an `exe` extension + try fm.copyItem(atPath: path, toPath: exePath) + XCTAssertFalse(fm.isExecutableFile(atPath: exePath)) +#else // test executable if file has execute permissions try fm.setAttributes([.posixPermissions : NSNumber(value: Int16(0o0100))], ofItemAtPath: path) XCTAssertTrue(fm.isExecutableFile(atPath: path)) +#endif + + // test against the test bundle itself + let testFoundationBinary = try XCTUnwrap(testBundle().path(forAuxiliaryExecutable: "TestFoundation")) + XCTAssertTrue(fm.isExecutableFile(atPath: testFoundationBinary)) } catch let e { XCTFail("\(e)") }