| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| |
| #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT |
| #if canImport(SwiftFoundation) && !DEPLOYMENT_RUNTIME_OBJC |
| @testable import SwiftFoundation |
| #else |
| @testable import Foundation |
| #endif |
| #endif |
| |
| class TestFileManager : XCTestCase { |
| #if os(Windows) |
| let pathSep = "\\" |
| #else |
| let pathSep = "/" |
| #endif |
| |
| func test_createDirectory() { |
| let fm = FileManager.default |
| let path = NSTemporaryDirectory() + "testdir\(NSUUID().uuidString)" |
| |
| try? fm.removeItem(atPath: path) |
| |
| do { |
| try fm.createDirectory(atPath: path, withIntermediateDirectories: false, attributes: nil) |
| } catch { |
| XCTFail() |
| } |
| |
| // Ensure attempting to create the directory again fails gracefully. |
| XCTAssertNil(try? fm.createDirectory(atPath: path, withIntermediateDirectories:false, attributes:nil)) |
| |
| var isDir: ObjCBool = false |
| let exists = fm.fileExists(atPath: path, isDirectory: &isDir) |
| XCTAssertTrue(exists) |
| XCTAssertTrue(isDir.boolValue) |
| |
| do { |
| try fm.removeItem(atPath: path) |
| } catch { |
| XCTFail("Failed to clean up file") |
| } |
| |
| } |
| |
| func test_createFile() { |
| let fm = FileManager.default |
| let path = NSTemporaryDirectory() + "testfile\(NSUUID().uuidString)" |
| |
| try? fm.removeItem(atPath: path) |
| |
| XCTAssertTrue(fm.createFile(atPath: path, contents: Data(), attributes: nil)) |
| |
| var isDir: ObjCBool = false |
| let exists = fm.fileExists(atPath: path, isDirectory: &isDir) |
| XCTAssertTrue(exists) |
| XCTAssertFalse(isDir.boolValue) |
| |
| do { |
| try fm.removeItem(atPath: path) |
| } catch { |
| XCTFail("Failed to clean up file") |
| } |
| |
| #if os(Windows) |
| let permissions = NSNumber(value: Int16(0o700)) |
| #else |
| let permissions = NSNumber(value: Int16(0o753)) |
| #endif |
| let attributes = [FileAttributeKey.posixPermissions: permissions] |
| XCTAssertTrue(fm.createFile(atPath: path, contents: Data(), |
| attributes: attributes)) |
| guard let retrievedAtributes = try? fm.attributesOfItem(atPath: path) else { |
| XCTFail("Failed to retrieve file attributes from created file") |
| return |
| } |
| |
| XCTAssertTrue(retrievedAtributes.contains(where: { (attribute) -> Bool in |
| guard let attributeValue = attribute.value as? NSNumber else { |
| return false |
| } |
| return (attribute.key == .posixPermissions) |
| && (attributeValue == permissions) |
| })) |
| |
| do { |
| try fm.removeItem(atPath: path) |
| } catch { |
| XCTFail("Failed to clean up file") |
| } |
| } |
| |
| func test_creatingDirectoryWithShortIntermediatePath() { |
| let fileManager = FileManager.default |
| fileManager.changeCurrentDirectoryPath(NSTemporaryDirectory()) |
| |
| let relativePath = NSUUID().uuidString |
| |
| do { |
| try fileManager.createDirectory(atPath: relativePath, withIntermediateDirectories: true, attributes: nil) |
| try fileManager.removeItem(atPath: relativePath) |
| } catch { |
| XCTFail("Failed to create and clean up directory") |
| } |
| } |
| |
| func test_moveFile() { |
| let fm = FileManager.default |
| let path = NSTemporaryDirectory() + "testfile\(NSUUID().uuidString)" |
| let path2 = NSTemporaryDirectory() + "testfile2\(NSUUID().uuidString)" |
| |
| func cleanup() { |
| try? fm.removeItem(atPath: path) |
| try? fm.removeItem(atPath: path2) |
| } |
| |
| cleanup() |
| |
| XCTAssertTrue(fm.createFile(atPath: path, contents: Data(), attributes: nil)) |
| defer { cleanup() } |
| |
| do { |
| try fm.moveItem(atPath: path, toPath: path2) |
| } catch { |
| XCTFail("Failed to move file: \(error)") |
| } |
| } |
| |
| func test_fileSystemRepresentation() { |
| let str = "☃" |
| let result = FileManager.default.fileSystemRepresentation(withPath: str) |
| XCTAssertEqual(UInt8(bitPattern: result[0]), 0xE2) |
| XCTAssertEqual(UInt8(bitPattern: result[1]), 0x98) |
| XCTAssertEqual(UInt8(bitPattern: result[2]), 0x83) |
| |
| #if !DARWIN_COMPATIBILITY_TESTS // auto-released by Darwin's Foundation |
| result.deallocate() |
| #endif |
| } |
| |
| func test_fileExists() { |
| let fm = FileManager.default |
| let tmpDir = fm.temporaryDirectory.appendingPathComponent("testFileExistsDir") |
| let testFile = tmpDir.appendingPathComponent("testFile") |
| let goodSymLink = tmpDir.appendingPathComponent("goodSymLink") |
| let badSymLink = tmpDir.appendingPathComponent("badSymLink") |
| let dirSymLink = tmpDir.appendingPathComponent("dirSymlink") |
| |
| try? fm.removeItem(atPath: tmpDir.path) |
| |
| do { |
| try fm.createDirectory(atPath: tmpDir.path, withIntermediateDirectories: false, attributes: nil) |
| XCTAssertTrue(fm.createFile(atPath: testFile.path, contents: Data())) |
| try fm.createSymbolicLink(atPath: goodSymLink.path, withDestinationPath: testFile.path) |
| #if os(Windows) |
| // Creating a broken symlink is expected to fail on Windows |
| XCTAssertNil(try? fm.createSymbolicLink(atPath: badSymLink.path, withDestinationPath: "no_such_file")) |
| #else |
| try fm.createSymbolicLink(atPath: badSymLink.path, withDestinationPath: "no_such_file") |
| #endif |
| try fm.createSymbolicLink(atPath: dirSymLink.path, withDestinationPath: "..") |
| |
| var isDirFlag: ObjCBool = false |
| XCTAssertTrue(fm.fileExists(atPath: tmpDir.path)) |
| XCTAssertTrue(fm.fileExists(atPath: tmpDir.path, isDirectory: &isDirFlag)) |
| XCTAssertTrue(isDirFlag.boolValue) |
| |
| isDirFlag = true |
| XCTAssertTrue(fm.fileExists(atPath: testFile.path)) |
| XCTAssertTrue(fm.fileExists(atPath: testFile.path, isDirectory: &isDirFlag)) |
| XCTAssertFalse(isDirFlag.boolValue) |
| |
| isDirFlag = true |
| XCTAssertTrue(fm.fileExists(atPath: goodSymLink.path)) |
| XCTAssertTrue(fm.fileExists(atPath: goodSymLink.path, isDirectory: &isDirFlag)) |
| XCTAssertFalse(isDirFlag.boolValue) |
| |
| isDirFlag = true |
| XCTAssertFalse(fm.fileExists(atPath: badSymLink.path)) |
| XCTAssertFalse(fm.fileExists(atPath: badSymLink.path, isDirectory: &isDirFlag)) |
| |
| isDirFlag = false |
| XCTAssertTrue(fm.fileExists(atPath: dirSymLink.path)) |
| XCTAssertTrue(fm.fileExists(atPath: dirSymLink.path, isDirectory: &isDirFlag)) |
| XCTAssertTrue(isDirFlag.boolValue) |
| } catch { |
| XCTFail(String(describing: error)) |
| } |
| try? fm.removeItem(atPath: tmpDir.path) |
| } |
| |
| func test_isReadableFile() { |
| let fm = FileManager.default |
| let path = NSTemporaryDirectory() + "test_isReadableFile\(NSUUID().uuidString)" |
| |
| do { |
| // create test file |
| XCTAssertTrue(fm.createFile(atPath: path, contents: Data())) |
| |
| // test unReadable if file has no permissions |
| try fm.setAttributes([.posixPermissions : NSNumber(value: Int16(0o0000))], ofItemAtPath: path) |
| #if os(Windows) |
| // Files are always readable on Windows |
| XCTAssertTrue(fm.isReadableFile(atPath: path)) |
| #else |
| XCTAssertFalse(fm.isReadableFile(atPath: path)) |
| #endif |
| |
| // test readable if file has read permissions |
| try fm.setAttributes([.posixPermissions : NSNumber(value: Int16(0o0400))], ofItemAtPath: path) |
| XCTAssertTrue(fm.isReadableFile(atPath: path)) |
| } catch let e { |
| XCTFail("\(e)") |
| } |
| } |
| |
| func test_isWritableFile() { |
| let fm = FileManager.default |
| let path = NSTemporaryDirectory() + "test_isWritableFile\(NSUUID().uuidString)" |
| |
| do { |
| // create test file |
| XCTAssertTrue(fm.createFile(atPath: path, contents: Data())) |
| |
| // test unWritable if file has no permissions |
| try fm.setAttributes([.posixPermissions : NSNumber(value: Int16(0o0000))], ofItemAtPath: path) |
| XCTAssertFalse(fm.isWritableFile(atPath: path)) |
| |
| // test writable if file has write permissions |
| try fm.setAttributes([.posixPermissions : NSNumber(value: Int16(0o0200))], ofItemAtPath: path) |
| XCTAssertTrue(fm.isWritableFile(atPath: path)) |
| } catch let e { |
| XCTFail("\(e)") |
| } |
| } |
| |
| func test_isExecutableFile() { |
| let fm = FileManager.default |
| let path = NSTemporaryDirectory() + "test_isExecutableFile\(NSUUID().uuidString)" |
| |
| do { |
| // create test file |
| XCTAssertTrue(fm.createFile(atPath: path, contents: Data())) |
| |
| // 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 |
| |
| // test executable if file has execute permissions |
| try fm.setAttributes([.posixPermissions : NSNumber(value: Int16(0o0100))], ofItemAtPath: path) |
| XCTAssertTrue(fm.isExecutableFile(atPath: path)) |
| } catch let e { |
| XCTFail("\(e)") |
| } |
| } |
| |
| func test_isDeletableFile() { |
| let fm = FileManager.default |
| |
| do { |
| let dir_path = NSTemporaryDirectory() + "/test_isDeletableFile_dir/" |
| let file_path = dir_path + "test_isDeletableFile\(NSUUID().uuidString)" |
| // create test directory |
| try fm.createDirectory(atPath: dir_path, withIntermediateDirectories: true) |
| // create test file |
| XCTAssertTrue(fm.createFile(atPath: file_path, contents: Data())) |
| |
| // test undeletable if parent directory has no permissions |
| try fm.setAttributes([.posixPermissions : NSNumber(value: Int16(0o0000))], ofItemAtPath: dir_path) |
| XCTAssertFalse(fm.isDeletableFile(atPath: file_path)) |
| |
| // test deletable if parent directory has all necessary permissions |
| try fm.setAttributes([.posixPermissions : NSNumber(value: Int16(0o0755))], ofItemAtPath: dir_path) |
| XCTAssertTrue(fm.isDeletableFile(atPath: file_path)) |
| } |
| catch { XCTFail("\(error)") } |
| |
| // test against known undeletable file |
| XCTAssertFalse(fm.isDeletableFile(atPath: "/dev/null")) |
| } |
| |
| func test_fileAttributes() throws { |
| let fm = FileManager.default |
| let path = NSTemporaryDirectory() + "test_fileAttributes\(NSUUID().uuidString)" |
| |
| try? fm.removeItem(atPath: path) |
| |
| XCTAssertTrue(fm.createFile(atPath: path, contents: Data(), attributes: nil)) |
| |
| do { |
| let attrs = try fm.attributesOfItem(atPath: path) |
| |
| XCTAssertTrue(attrs.count > 0) |
| |
| let fileSize = attrs[.size] as? NSNumber |
| XCTAssertEqual(fileSize!.int64Value, 0) |
| |
| let fileModificationDate = attrs[.modificationDate] as? Date |
| XCTAssertGreaterThan(Date().timeIntervalSince1970, fileModificationDate!.timeIntervalSince1970) |
| |
| let filePosixPermissions = attrs[.posixPermissions] as? NSNumber |
| XCTAssertNotEqual(filePosixPermissions!.int64Value, 0) |
| |
| let fileReferenceCount = attrs[.referenceCount] as? NSNumber |
| XCTAssertEqual(fileReferenceCount!.int64Value, 1) |
| |
| let fileSystemNumber = attrs[.systemNumber] as? NSNumber |
| XCTAssertNotEqual(fileSystemNumber!.int64Value, 0) |
| |
| #if !os(Windows) |
| let fileSystemFileNumber = attrs[.systemFileNumber] as? NSNumber |
| XCTAssertNotEqual(fileSystemFileNumber!.int64Value, 0) |
| #endif |
| |
| let fileType = attrs[.type] as? FileAttributeType |
| XCTAssertEqual(fileType!, .typeRegular) |
| |
| let fileOwnerAccountID = attrs[.ownerAccountID] as? NSNumber |
| XCTAssertNotNil(fileOwnerAccountID) |
| |
| let fileGroupOwnerAccountID = attrs[.groupOwnerAccountID] as? NSNumber |
| XCTAssertNotNil(fileGroupOwnerAccountID) |
| |
| #if os(Linux) |
| /* ⚠️ */ |
| if shouldAttemptXFailTests("Checking that .creationDate is set is failing on Ubuntu 16.04 when running from a Docker image. https://bugs.swift.org/browse/SR-10512") { |
| let requiredVersion = OperatingSystemVersion(majorVersion: 4, minorVersion: 11, patchVersion: 0) |
| let creationDate = attrs[.creationDate] as? Date |
| if ProcessInfo.processInfo.isOperatingSystemAtLeast(requiredVersion) { |
| XCTAssertNotNil(creationDate) |
| XCTAssertGreaterThan(Date().timeIntervalSince1970, try XCTUnwrap(creationDate).timeIntervalSince1970) |
| } else { |
| XCTAssertNil(creationDate) |
| } |
| } |
| /* ⚠️ */ |
| #endif |
| |
| if let fileOwnerAccountName = attrs[.ownerAccountName] { |
| XCTAssertNotNil(fileOwnerAccountName as? String) |
| if let fileOwnerAccountNameStr = fileOwnerAccountName as? String { |
| XCTAssertFalse(fileOwnerAccountNameStr.isEmpty) |
| } |
| } |
| |
| if let fileGroupOwnerAccountName = attrs[.groupOwnerAccountName] { |
| XCTAssertNotNil(fileGroupOwnerAccountName as? String) |
| if let fileGroupOwnerAccountNameStr = fileGroupOwnerAccountName as? String { |
| XCTAssertFalse(fileGroupOwnerAccountNameStr.isEmpty) |
| } |
| } |
| |
| } catch { |
| XCTFail("\(error)") |
| } |
| |
| do { |
| try fm.removeItem(atPath: path) |
| } catch { |
| XCTFail("Failed to clean up files") |
| } |
| } |
| |
| func test_fileSystemAttributes() { |
| let fm = FileManager.default |
| let path = NSTemporaryDirectory() |
| |
| do { |
| let attrs = try fm.attributesOfFileSystem(forPath: path) |
| |
| XCTAssertTrue(attrs.count > 0) |
| |
| let systemNumber = attrs[.systemNumber] as? NSNumber |
| XCTAssertNotNil(systemNumber) |
| |
| let systemFreeSize = attrs[.systemFreeSize] as? NSNumber |
| XCTAssertNotNil(systemFreeSize) |
| XCTAssertNotEqual(systemFreeSize!.uint64Value, 0) |
| |
| let systemSize = attrs[.systemSize] as? NSNumber |
| XCTAssertNotNil(systemSize) |
| XCTAssertGreaterThan(systemSize!.uint64Value, systemFreeSize!.uint64Value) |
| |
| if shouldAttemptWindowsXFailTests("FileAttributes[.systemFreeNodes], FileAttributes[.systemNodes] not implemented") { |
| let systemFreeNodes = attrs[.systemFreeNodes] as? NSNumber |
| XCTAssertNotNil(systemFreeNodes) |
| XCTAssertNotEqual(systemFreeNodes!.uint64Value, 0) |
| |
| let systemNodes = attrs[.systemNodes] as? NSNumber |
| XCTAssertNotNil(systemNodes) |
| XCTAssertGreaterThan(systemNodes!.uint64Value, systemFreeNodes!.uint64Value) |
| } |
| } catch { |
| XCTFail("\(error)") |
| } |
| } |
| |
| func test_setFileAttributes() { |
| let path = NSTemporaryDirectory() + "test_setFileAttributes\(NSUUID().uuidString)" |
| let fm = FileManager.default |
| |
| try? fm.removeItem(atPath: path) |
| XCTAssertTrue(fm.createFile(atPath: path, contents: Data(), attributes: nil)) |
| |
| do { |
| try fm.setAttributes([.posixPermissions : NSNumber(value: Int16(0o0600))], ofItemAtPath: path) |
| } |
| catch { XCTFail("\(error)") } |
| |
| //read back the attributes |
| do { |
| let attributes = try fm.attributesOfItem(atPath: path) |
| #if os(Windows) |
| XCTAssert((attributes[.posixPermissions] as? NSNumber)?.int16Value == 0o0700) |
| #else |
| XCTAssert((attributes[.posixPermissions] as? NSNumber)?.int16Value == 0o0600) |
| #endif |
| } |
| catch { XCTFail("\(error)") } |
| |
| do { |
| try fm.removeItem(atPath: path) |
| } catch { |
| XCTFail("Failed to clean up files") |
| } |
| |
| // test non existent file |
| let noSuchFile = NSTemporaryDirectory() + "fileThatDoesntExist" |
| try? fm.removeItem(atPath: noSuchFile) |
| do { |
| try fm.setAttributes([.posixPermissions: 0], ofItemAtPath: noSuchFile) |
| XCTFail("Setting permissions of non-existent file should throw") |
| } catch { |
| } |
| } |
| |
| func test_pathEnumerator() { |
| let fm = FileManager.default |
| let testDirName = "testdir\(NSUUID().uuidString)" |
| let basePath = NSTemporaryDirectory() + "\(testDirName)" |
| let itemPath = NSTemporaryDirectory() + "\(testDirName)/item" |
| let basePath2 = NSTemporaryDirectory() + "\(testDirName)/path2" |
| let itemPath2 = NSTemporaryDirectory() + "\(testDirName)/path2/item" |
| |
| try? fm.removeItem(atPath: basePath) |
| |
| do { |
| try fm.createDirectory(atPath: basePath, withIntermediateDirectories: false, attributes: nil) |
| try fm.createDirectory(atPath: basePath2, withIntermediateDirectories: false, attributes: nil) |
| |
| let _ = fm.createFile(atPath: itemPath, contents: Data(count: 123), attributes: nil) |
| let _ = fm.createFile(atPath: itemPath2, contents: Data(count: 456), attributes: nil) |
| |
| } catch { |
| XCTFail() |
| } |
| |
| var item1FileAttributes: [FileAttributeKey: Any]! |
| var item2FileAttributes: [FileAttributeKey: Any]! |
| if let e = FileManager.default.enumerator(atPath: basePath) { |
| let attrs = e.directoryAttributes |
| XCTAssertNotNil(attrs) |
| XCTAssertEqual(attrs?[.type] as? FileAttributeType, .typeDirectory) |
| |
| var foundItems = Set<String>() |
| while let item = e.nextObject() as? String { |
| foundItems.insert(item) |
| if item == "item" { |
| item1FileAttributes = e.fileAttributes |
| } else if item == "path2\(pathSep)item" { |
| item2FileAttributes = e.fileAttributes |
| } |
| } |
| XCTAssertEqual(foundItems, Set(["item", "path2", "path2\(pathSep)item"])) |
| } else { |
| XCTFail() |
| } |
| |
| XCTAssertNotNil(item1FileAttributes) |
| if let size = item1FileAttributes[.size] as? NSNumber { |
| XCTAssertEqual(size.int64Value, 123) |
| } else { |
| XCTFail("Cant get file size for 'item'") |
| } |
| |
| XCTAssertNotNil(item2FileAttributes) |
| if let size = item2FileAttributes[.size] as? NSNumber { |
| XCTAssertEqual(size.int64Value, 456) |
| } else { |
| XCTFail("Cant get file size for 'path2/item'") |
| } |
| |
| if let e2 = FileManager.default.enumerator(atPath: basePath) { |
| var foundItems = Set<String>() |
| while let item = e2.nextObject() as? String { |
| foundItems.insert(item) |
| if item == "path2" { |
| e2.skipDescendants() |
| XCTAssertEqual(e2.level, 1) |
| XCTAssertNotNil(e2.fileAttributes) |
| } |
| } |
| XCTAssertEqual(foundItems, Set(["item", "path2"])) |
| } else { |
| XCTFail() |
| } |
| } |
| |
| func test_directoryEnumerator() { |
| let fm = FileManager.default |
| let basePath = NSTemporaryDirectory() + "testdir\(NSUUID().uuidString)/" |
| let hiddenDir1 = basePath + "subdir1/subdir2/.hiddenDir/" |
| let subDirs1 = hiddenDir1 + "subdir3/" |
| let itemPath1 = basePath + "itemFile1" |
| #if os(Windows) |
| // Filenames ending with '.' are not valid on Windows, so don't bother testing them |
| let hiddenDir2 = basePath + "subdir1/subdir2/subdir4.app/subdir5/.subdir6.ext/" |
| let subDirs2 = hiddenDir2 + "subdir7.ext/" |
| let itemPath2 = subDirs1 + "itemFile2" |
| let itemPath3 = subDirs1 + "itemFile3.ext" |
| #else |
| let hiddenDir2 = basePath + "subdir1/subdir2/subdir4.app/subdir5./.subdir6.ext/" |
| let subDirs2 = hiddenDir2 + "subdir7.ext./" |
| let itemPath2 = subDirs1 + "itemFile2." |
| let itemPath3 = subDirs1 + "itemFile3.ext." |
| #endif |
| let hiddenItem1 = basePath + ".hiddenFile1" |
| let hiddenItem2 = subDirs1 + ".hiddenFile2" |
| let hiddenItem3 = subDirs2 + ".hiddenFile3" |
| let hiddenItem4 = subDirs2 + ".hiddenFile4.ext" |
| |
| var fileLevels: [String: Int] = [ |
| "itemFile1": 1, |
| ".hiddenFile1": 1, |
| "subdir1": 1, |
| "subdir2": 2, |
| "subdir4.app": 3, |
| ".subdir6.ext": 5, |
| ".hiddenFile4.ext": 7, |
| ".hiddenFile3": 7, |
| ".hiddenDir": 3, |
| "subdir3": 4, |
| ".hiddenFile2": 5, |
| ] |
| #if os(Windows) |
| fileLevels["itemFile2"] = 5 |
| fileLevels["subdir5"] = 4 |
| fileLevels["subdir7.ext"] = 6 |
| fileLevels["itemFile3.ext"] = 5 |
| #else |
| fileLevels["itemFile2."] = 5 |
| fileLevels["subdir5."] = 4 |
| fileLevels["subdir7.ext."] = 6 |
| fileLevels["itemFile3.ext."] = 5 |
| #endif |
| |
| func directoryItems(options: FileManager.DirectoryEnumerationOptions) -> [String: Int]? { |
| if let e = FileManager.default.enumerator(at: URL(fileURLWithPath: basePath), includingPropertiesForKeys: nil, options: options, errorHandler: nil) { |
| var foundItems = [String:Int]() |
| while let item = e.nextObject() as? URL { |
| foundItems[item.lastPathComponent] = e.level |
| } |
| return foundItems |
| } else { |
| return nil |
| } |
| } |
| |
| try? fm.removeItem(atPath: basePath) |
| defer { try? fm.removeItem(atPath: basePath) } |
| |
| XCTAssertNotNil(try? fm.createDirectory(atPath: subDirs1, withIntermediateDirectories: true, attributes: nil)) |
| XCTAssertNotNil(try? fm.createDirectory(atPath: subDirs2, withIntermediateDirectories: true, attributes: nil)) |
| for filename in [itemPath1, itemPath2, itemPath3] { |
| XCTAssertTrue(fm.createFile(atPath: filename, contents: Data(), attributes: nil), "Cant create file '\(filename)'") |
| } |
| |
| var resourceValues = URLResourceValues() |
| resourceValues.isHidden = true |
| for filename in [ hiddenItem1, hiddenItem2, hiddenItem3, hiddenItem4] { |
| XCTAssertTrue(fm.createFile(atPath: filename, contents: Data(), attributes: nil), "Cant create file '\(filename)'") |
| #if os(Windows) |
| do { |
| var url = URL(fileURLWithPath: filename) |
| try url.setResourceValues(resourceValues) |
| } catch { |
| XCTFail("Couldn't make \(filename) a hidden file") |
| } |
| #endif |
| } |
| |
| #if os(Windows) |
| do { |
| var hiddenURL1 = URL(fileURLWithPath: hiddenDir1) |
| var hiddenURL2 = URL(fileURLWithPath: hiddenDir2) |
| try hiddenURL1.setResourceValues(resourceValues) |
| try hiddenURL2.setResourceValues(resourceValues) |
| } catch { |
| XCTFail("Couldn't make \(hiddenDir1) and \(hiddenDir2) hidden directories") |
| } |
| #endif |
| |
| if let foundItems = directoryItems(options: []) { |
| XCTAssertEqual(foundItems.count, fileLevels.count) |
| for (name, level) in foundItems { |
| XCTAssertEqual(fileLevels[name], level, "File level for \(name) is wrong") |
| } |
| } else { |
| XCTFail("Cant enumerate directory at \(basePath) with options: []") |
| } |
| |
| if let foundItems = directoryItems(options: [.skipsHiddenFiles]) { |
| XCTAssertEqual(foundItems.count, 5) |
| } else { |
| XCTFail("Cant enumerate directory at \(basePath) with options: [.skipsHiddenFiles]") |
| } |
| |
| if let foundItems = directoryItems(options: [.skipsSubdirectoryDescendants]) { |
| XCTAssertEqual(foundItems.count, 3) |
| } else { |
| XCTFail("Cant enumerate directory at \(basePath) with options: [.skipsSubdirectoryDescendants]") |
| } |
| |
| if let foundItems = directoryItems(options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants]) { |
| XCTAssertEqual(foundItems.count, 2) |
| } else { |
| XCTFail("Cant enumerate directory at \(basePath) with options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants]") |
| } |
| |
| if let foundItems = directoryItems(options: [.skipsPackageDescendants]) { |
| #if DARWIN_COMPATIBILITY_TESTS |
| XCTAssertEqual(foundItems.count, 10) // Only native Foundation does not gnore .skipsPackageDescendants |
| #else |
| XCTAssertEqual(foundItems.count, 15) |
| #endif |
| } else { |
| XCTFail("Cant enumerate directory at \(basePath) with options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants]") |
| } |
| |
| var didGetError = false |
| let handler : (URL, Error) -> Bool = { (URL, Error) in |
| didGetError = true |
| return true |
| } |
| if let e = FileManager.default.enumerator(at: URL(fileURLWithPath: "/nonexistent-path"), includingPropertiesForKeys: nil, options: [], errorHandler: handler) { |
| XCTAssertNil(e.nextObject()) |
| } else { |
| XCTFail() |
| } |
| XCTAssertTrue(didGetError) |
| |
| do { |
| let contents = try FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: basePath), includingPropertiesForKeys: nil, options: []).map { |
| return $0.path |
| } |
| XCTAssertEqual(contents.count, 3) |
| } catch { |
| XCTFail() |
| } |
| } |
| |
| func test_contentsOfDirectoryAtPath() { |
| let fm = FileManager.default |
| let testDirName = "testdir\(NSUUID().uuidString)" |
| let path = NSTemporaryDirectory() + "\(testDirName)" |
| let itemPath1 = NSTemporaryDirectory() + "\(testDirName)/item" |
| let itemPath2 = NSTemporaryDirectory() + "\(testDirName)/item2" |
| |
| try? fm.removeItem(atPath: path) |
| |
| do { |
| try fm.createDirectory(atPath: path, withIntermediateDirectories: false, attributes: nil) |
| let _ = fm.createFile(atPath: itemPath1, contents: Data(), attributes: nil) |
| let _ = fm.createFile(atPath: itemPath2, contents: Data(), attributes: nil) |
| } catch { |
| XCTFail() |
| } |
| |
| do { |
| let entries = try fm.contentsOfDirectory(atPath: path) |
| |
| XCTAssertEqual(2, entries.count) |
| XCTAssertTrue(entries.contains("item")) |
| XCTAssertTrue(entries.contains("item2")) |
| } |
| catch { |
| XCTFail() |
| } |
| |
| do { |
| // Check a bad path fails |
| let _ = try fm.contentsOfDirectory(atPath: "/...") |
| XCTFail() |
| } |
| catch { |
| // Invalid directories should fail. |
| } |
| |
| do { |
| try fm.removeItem(atPath: path) |
| } catch { |
| XCTFail("Failed to clean up files") |
| } |
| } |
| |
| func test_subpathsOfDirectoryAtPath() { |
| let fm = FileManager.default |
| let path = NSTemporaryDirectory() + "testdir" |
| let path2 = NSTemporaryDirectory() + "testdir/sub" |
| let itemPath1 = NSTemporaryDirectory() + "testdir/item" |
| let itemPath2 = NSTemporaryDirectory() + "testdir/item2" |
| let itemPath3 = NSTemporaryDirectory() + "testdir/sub/item3" |
| |
| try? fm.removeItem(atPath: path) |
| |
| do { |
| try fm.createDirectory(atPath: path, withIntermediateDirectories: false, attributes: nil) |
| let _ = fm.createFile(atPath: itemPath1, contents: Data(), attributes: nil) |
| let _ = fm.createFile(atPath: itemPath2, contents: Data(), attributes: nil) |
| |
| try fm.createDirectory(atPath: path2, withIntermediateDirectories: false, attributes: nil) |
| let _ = fm.createFile(atPath: itemPath3, contents: Data(), attributes: nil) |
| } catch { |
| XCTFail() |
| } |
| |
| do { |
| let entries = try fm.subpathsOfDirectory(atPath: path) |
| |
| XCTAssertEqual(4, entries.count) |
| XCTAssertTrue(entries.contains("item")) |
| XCTAssertTrue(entries.contains("item2")) |
| XCTAssertTrue(entries.contains("sub")) |
| XCTAssertTrue(entries.contains("sub/item3")) |
| XCTAssertEqual(fm.subpaths(atPath: path), entries) |
| } |
| catch { |
| XCTFail() |
| } |
| |
| do { |
| // Check a bad path fails |
| XCTAssertNil(fm.subpaths(atPath: "/...")) |
| |
| let _ = try fm.subpathsOfDirectory(atPath: "/...") |
| XCTFail() |
| } |
| catch { |
| // Invalid directories should fail. |
| } |
| |
| do { |
| try fm.removeItem(atPath: path) |
| } catch { |
| XCTFail("Failed to clean up files") |
| } |
| } |
| |
| private func directoryExists(atPath path: String) -> Bool { |
| var isDir: ObjCBool = false |
| let exists = FileManager.default.fileExists(atPath: path, isDirectory: &isDir) |
| return exists && isDir.boolValue |
| } |
| |
| func test_copyItemAtPathToPath() { |
| let fm = FileManager.default |
| let srcPath = NSTemporaryDirectory() + "testdir\(NSUUID().uuidString)" |
| let destPath = NSTemporaryDirectory() + "testdir\(NSUUID().uuidString)" |
| |
| func cleanup() { |
| try? fm.removeItem(atPath: srcPath) |
| try? fm.removeItem(atPath: destPath) |
| } |
| |
| func createDirectory(atPath path: String) { |
| do { |
| try fm.createDirectory(atPath: path, withIntermediateDirectories: false, attributes: nil) |
| } catch { |
| XCTFail("Unable to create directory: \(error)") |
| } |
| XCTAssertTrue(directoryExists(atPath: path)) |
| } |
| |
| func createFile(atPath path: String) { |
| XCTAssertTrue(fm.createFile(atPath: path, contents: Data(), attributes: nil)) |
| } |
| |
| cleanup() |
| createFile(atPath: srcPath) |
| do { |
| try fm.copyItem(atPath: srcPath, toPath: destPath) |
| } catch { |
| XCTFail("Failed to copy file: \(error)") |
| } |
| |
| cleanup() |
| createDirectory(atPath: srcPath) |
| createDirectory(atPath: "\(srcPath)/tempdir") |
| createDirectory(atPath: "\(srcPath)/tempdir/subdir") |
| createDirectory(atPath: "\(srcPath)/tempdir/subdir/otherdir") |
| createDirectory(atPath: "\(srcPath)/tempdir/subdir/otherdir/extradir") |
| createFile(atPath: "\(srcPath)/tempdir/tempfile") |
| createFile(atPath: "\(srcPath)/tempdir/tempfile2") |
| createFile(atPath: "\(srcPath)/tempdir/subdir/otherdir/extradir/tempfile2") |
| |
| do { |
| try fm.copyItem(atPath: srcPath, toPath: destPath) |
| } catch { |
| XCTFail("Unable to copy directory: \(error)") |
| } |
| XCTAssertTrue(directoryExists(atPath: destPath)) |
| XCTAssertTrue(directoryExists(atPath: "\(destPath)/tempdir")) |
| XCTAssertTrue(fm.fileExists(atPath: "\(destPath)/tempdir/tempfile")) |
| XCTAssertTrue(fm.fileExists(atPath: "\(destPath)/tempdir/tempfile2")) |
| XCTAssertTrue(directoryExists(atPath: "\(destPath)/tempdir/subdir/otherdir/extradir")) |
| XCTAssertTrue(fm.fileExists(atPath: "\(destPath)/tempdir/subdir/otherdir/extradir/tempfile2")) |
| |
| if (false == directoryExists(atPath: destPath)) { |
| return |
| } |
| do { |
| try fm.copyItem(atPath: srcPath, toPath: destPath) |
| XCTFail("Copy overwrites a file/folder that already exists") |
| } catch { |
| // ignore |
| } |
| |
| // Test copying a symlink |
| let srcLink = srcPath + "/testlink" |
| let destLink = destPath + "/testlink" |
| do { |
| #if os(Windows) |
| fm.createFile(atPath: srcPath.appendingPathComponent("linkdest"), contents: Data(), attributes: nil) |
| #endif |
| try fm.createSymbolicLink(atPath: srcLink, withDestinationPath: "linkdest") |
| try fm.copyItem(atPath: srcLink, toPath: destLink) |
| XCTAssertEqual(try fm.destinationOfSymbolicLink(atPath: destLink), "linkdest") |
| } catch { |
| XCTFail("\(error)") |
| } |
| |
| do { |
| try fm.copyItem(atPath: srcLink, toPath: destLink) |
| XCTFail("Creating link where one already exists") |
| } catch { |
| // ignore |
| } |
| } |
| |
| func test_linkItemAtPathToPath() { |
| let fm = FileManager.default |
| let basePath = NSTemporaryDirectory() + "linkItemAtPathToPath/" |
| let srcPath = basePath + "testdir\(NSUUID().uuidString)" |
| let destPath = basePath + "testdir\(NSUUID().uuidString)" |
| defer { try? fm.removeItem(atPath: basePath) } |
| |
| func getFileInfo(atPath path: String, _ body: (String, Bool, UInt64, UInt64) -> ()) { |
| guard let enumerator = fm.enumerator(atPath: path) else { |
| XCTFail("Cant enumerate \(path)") |
| return |
| } |
| while let item = enumerator.nextObject() as? String { |
| let fname = "\(path)/\(item)" |
| do { |
| let attrs = try fm.attributesOfItem(atPath: fname) |
| let inode = (attrs[.systemFileNumber] as? NSNumber)?.uint64Value |
| let linkCount = (attrs[.referenceCount] as? NSNumber)?.uint64Value |
| let ftype = attrs[.type] as? FileAttributeType |
| |
| if inode == nil || linkCount == nil || ftype == nil { |
| XCTFail("Unable to get attributes of \(fname)") |
| return |
| } |
| let isDir = (ftype == .typeDirectory) |
| body(item, isDir, inode!, linkCount!) |
| } catch { |
| XCTFail("Unable to get attributes of \(fname): \(error)") |
| return |
| } |
| } |
| } |
| |
| try? fm.removeItem(atPath: basePath) |
| XCTAssertNotNil(try? fm.createDirectory(atPath: "\(srcPath)/tempdir/subdir/otherdir/extradir", withIntermediateDirectories: true, attributes: nil)) |
| XCTAssertTrue(fm.createFile(atPath: "\(srcPath)/tempdir/tempfile", contents: Data(), attributes: nil)) |
| XCTAssertTrue(fm.createFile(atPath: "\(srcPath)/tempdir/tempfile2", contents: Data(), attributes: nil)) |
| XCTAssertTrue(fm.createFile(atPath: "\(srcPath)/tempdir/subdir/otherdir/extradir/tempfile2", contents: Data(), attributes: nil)) |
| |
| var fileInfos: [String: (Bool, UInt64, UInt64)] = [:] |
| getFileInfo(atPath: srcPath, { name, isDir, inode, linkCount in |
| fileInfos[name] = (isDir, inode, linkCount) |
| }) |
| XCTAssertEqual(fileInfos.count, 7) |
| XCTAssertNotNil(try? fm.linkItem(atPath: srcPath, toPath: destPath), "Unable to link directory") |
| |
| getFileInfo(atPath: destPath, { name, isDir, inode, linkCount in |
| guard let srcFileInfo = fileInfos.removeValue(forKey: name) else { |
| XCTFail("Cant find \(name) in \(destPath)") |
| return |
| } |
| let (srcIsDir, srcInode, srcLinkCount) = srcFileInfo |
| XCTAssertEqual(srcIsDir, isDir, "Directory/File type mismatch") |
| if isDir { |
| XCTAssertEqual(srcLinkCount, linkCount) |
| } else { |
| XCTAssertEqual(srcInode, inode) |
| XCTAssertEqual(srcLinkCount + 1, linkCount) |
| } |
| }) |
| |
| XCTAssertEqual(fileInfos.count, 0) |
| // linkItem should fail a 2nd time |
| XCTAssertNil(try? fm.linkItem(atPath: srcPath, toPath: destPath), "Copy overwrites a file/folder that already exists") |
| |
| // Test 'linking' a symlink, which actually does a copy |
| let srcLink = srcPath + "/testlink" |
| let destLink = destPath + "/testlink" |
| do { |
| #if os(Windows) |
| fm.createFile(atPath: srcPath.appendingPathComponent("linkdest"), contents: Data(), attributes: nil) |
| #endif |
| try fm.createSymbolicLink(atPath: srcLink, withDestinationPath: "linkdest") |
| try fm.linkItem(atPath: srcLink, toPath: destLink) |
| XCTAssertEqual(try fm.destinationOfSymbolicLink(atPath: destLink), "linkdest") |
| } catch { |
| XCTFail("\(error)") |
| } |
| XCTAssertNil(try? fm.linkItem(atPath: srcLink, toPath: destLink), "Creating link where one already exists") |
| } |
| |
| func test_homedirectoryForUser() { |
| let filemanger = FileManager.default |
| XCTAssertNil(filemanger.homeDirectory(forUser: "someuser")) |
| XCTAssertNil(filemanger.homeDirectory(forUser: "")) |
| XCTAssertNotNil(filemanger.homeDirectoryForCurrentUser) |
| } |
| |
| func test_temporaryDirectoryForUser() { |
| let filemanger = FileManager.default |
| let tmpDir = filemanger.temporaryDirectory |
| let tmpFileUrl = tmpDir.appendingPathComponent("test.bin") |
| let tmpFilePath = tmpFileUrl.path |
| |
| do { |
| if filemanger.fileExists(atPath: tmpFilePath) { |
| try filemanger.removeItem(at: tmpFileUrl) |
| } |
| |
| try "hello world".write(to: tmpFileUrl, atomically: false, encoding: .utf8) |
| XCTAssert(filemanger.fileExists(atPath: tmpFilePath)) |
| |
| try filemanger.removeItem(at: tmpFileUrl) |
| } catch { |
| XCTFail("Unable to write a file to the temporary directory: \(tmpDir), err: \(error)") |
| } |
| } |
| |
| func test_mountedVolumeURLs() { |
| guard let volumes = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys:[], options: []) else { |
| XCTFail("mountedVolumeURLs returned nil") |
| return |
| } |
| XCTAssertNotEqual(0, volumes.count) |
| XCTAssertTrue(volumes.contains(URL(fileURLWithPath: "/"))) |
| #if os(macOS) |
| // On macOS, .skipHiddenVolumes should hide 'nobrowse' volumes of which there should be at least one |
| guard let visibleVolumes = FileManager.default.mountedVolumeURLs(includingResourceValuesForKeys: [], options: [.skipHiddenVolumes]) else { |
| XCTFail("mountedVolumeURLs returned nil") |
| return |
| } |
| XCTAssertTrue(visibleVolumes.count > 0) |
| XCTAssertTrue(visibleVolumes.count < volumes.count) |
| #endif |
| } |
| |
| func test_contentsEqual() { |
| let fm = FileManager.default |
| let tmpParentDirURL = URL(fileURLWithPath: NSTemporaryDirectory() + "test_contentsEqualdir", isDirectory: true) |
| let testDir1 = tmpParentDirURL.appendingPathComponent("testDir1") |
| let testDir2 = tmpParentDirURL.appendingPathComponent("testDir2") |
| let testDir3 = testDir1.appendingPathComponent("subDir/anotherDir/extraDir/lastDir") |
| |
| defer { try? fm.removeItem(atPath: tmpParentDirURL.path) } |
| |
| func testFileURL(_ name: String, _ ext: String) -> URL? { |
| guard let url = testBundle().url(forResource: name, withExtension: ext) else { |
| XCTFail("Cant open \(name).\(ext)") |
| return nil |
| } |
| return url |
| } |
| |
| guard let testFile1URL = testFileURL("NSStringTestData", "txt") else { return } |
| guard let testFile2URL = testFileURL("NSURLTestData", "plist") else { return } |
| guard let testFile3URL = testFileURL("NSString-UTF32-BE-data", "txt") else { return } |
| guard let testFile4URL = testFileURL("NSString-UTF32-LE-data", "txt") else { return } |
| let symlink = testDir1.appendingPathComponent("testlink").path |
| |
| // Setup test directories |
| do { |
| // Clean out and leftover test data |
| try? fm.removeItem(atPath: tmpParentDirURL.path) |
| |
| // testDir1 |
| try fm.createDirectory(atPath: testDir1.path, withIntermediateDirectories: true) |
| #if !os(Windows) |
| try fm.createSymbolicLink(atPath: testDir1.appendingPathComponent("null1").path, withDestinationPath: "/dev/null") |
| try fm.createSymbolicLink(atPath: testDir1.appendingPathComponent("zero1").path, withDestinationPath: "/dev/zero") |
| #endif |
| try "foo".write(toFile: testDir1.appendingPathComponent("foo.txt").path, atomically: false, encoding: .ascii) |
| try fm.createSymbolicLink(atPath: testDir1.appendingPathComponent("foo1").path, withDestinationPath: "foo.txt") |
| try fm.createSymbolicLink(atPath: testDir1.appendingPathComponent("bar2").path, withDestinationPath: "foo1") |
| let unreadable = testDir1.appendingPathComponent("unreadable_file").path |
| try "unreadable".write(toFile: unreadable, atomically: false, encoding: .ascii) |
| try fm.setAttributes([.posixPermissions: NSNumber(value: 0)], ofItemAtPath: unreadable) |
| try Data().write(to: testDir1.appendingPathComponent("empty_file")) |
| try fm.createSymbolicLink(atPath: symlink, withDestinationPath: testFile1URL.path) |
| |
| try fm.createSymbolicLink(atPath: testDir1.appendingPathComponent("thisDir").path, withDestinationPath: ".") |
| try fm.createSymbolicLink(atPath: testDir1.appendingPathComponent("parentDir").path, withDestinationPath: "..") |
| try fm.createSymbolicLink(atPath: testDir1.appendingPathComponent("rootDir").path, withDestinationPath: "/") |
| |
| // testDir2 |
| try fm.createDirectory(atPath: testDir2.path, withIntermediateDirectories: true) |
| #if os(Windows) |
| try "foo".write(toFile: testDir2.appendingPathComponent("foo1").path, atomically: false, encoding: .ascii) |
| try fm.createDirectory(atPath: testDir2.appendingPathComponent("../testDir1").path, withIntermediateDirectories: true) |
| try "foo".write(toFile: testDir2.appendingPathComponent("../testDir1/foo.txt").path, atomically: false, encoding: .ascii) |
| #endif |
| try fm.createSymbolicLink(atPath: testDir2.appendingPathComponent("bar2").path, withDestinationPath: "foo1") |
| try fm.createSymbolicLink(atPath: testDir2.appendingPathComponent("foo2").path, withDestinationPath: "../testDir1/foo.txt") |
| |
| // testDir3 |
| try fm.createDirectory(atPath: testDir3.path, withIntermediateDirectories: true) |
| #if os(Windows) |
| try fm.createDirectory(atPath: testDir3.appendingPathComponent("../testDir1").path, withIntermediateDirectories: true) |
| try "foo".write(toFile: testDir3.appendingPathComponent("../testDir1/foo.txt").path, atomically: false, encoding: .ascii) |
| try "foo".write(toFile: testDir3.appendingPathComponent("foo1").path, atomically: false, encoding: .ascii) |
| #endif |
| try fm.createSymbolicLink(atPath: testDir3.appendingPathComponent("bar2").path, withDestinationPath: "foo1") |
| try fm.createSymbolicLink(atPath: testDir3.appendingPathComponent("foo2").path, withDestinationPath: "../testDir1/foo.txt") |
| } catch { |
| XCTFail(String(describing: error)) |
| } |
| |
| #if os(Windows) |
| XCTAssertFalse(fm.contentsEqual(atPath: "NUL", andPath: "NUL")) |
| #else |
| XCTAssertTrue(fm.contentsEqual(atPath: "/dev/null", andPath: "/dev/null")) |
| XCTAssertTrue(fm.contentsEqual(atPath: "/dev/urandom", andPath: "/dev/urandom")) |
| XCTAssertFalse(fm.contentsEqual(atPath: "/dev/null", andPath: "/dev/zero")) |
| XCTAssertFalse(fm.contentsEqual(atPath: testDir1.appendingPathComponent("null1").path, andPath: "/dev/null")) |
| XCTAssertFalse(fm.contentsEqual(atPath: testDir1.appendingPathComponent("zero").path, andPath: "/dev/zero")) |
| #endif |
| XCTAssertFalse(fm.contentsEqual(atPath: testDir1.appendingPathComponent("foo.txt").path, andPath: testDir1.appendingPathComponent("foo1").path)) |
| XCTAssertFalse(fm.contentsEqual(atPath: testDir1.appendingPathComponent("foo.txt").path, andPath: testDir1.appendingPathComponent("foo2").path)) |
| XCTAssertTrue(fm.contentsEqual(atPath: testDir1.appendingPathComponent("bar2").path, andPath: testDir2.appendingPathComponent("bar2").path)) |
| XCTAssertFalse(fm.contentsEqual(atPath: testDir1.appendingPathComponent("foo1").path, andPath: testDir2.appendingPathComponent("foo2").path)) |
| XCTAssertFalse(fm.contentsEqual(atPath: "/non_existent_file", andPath: "/non_existent_file")) |
| |
| let emptyFile = testDir1.appendingPathComponent("empty_file") |
| #if os(Windows) |
| XCTAssertFalse(fm.contentsEqual(atPath: emptyFile.path, andPath: "NUL")) |
| #else |
| XCTAssertFalse(fm.contentsEqual(atPath: emptyFile.path, andPath: "/dev/null")) |
| #endif |
| XCTAssertFalse(fm.contentsEqual(atPath: emptyFile.path, andPath: testDir1.appendingPathComponent("null1").path)) |
| #if os(Windows) |
| // A file cannot be unreadable on Windows |
| XCTAssertTrue(fm.contentsEqual(atPath: emptyFile.path, andPath: testDir1.appendingPathComponent("unreadable_file").path)) |
| #else |
| XCTAssertFalse(fm.contentsEqual(atPath: emptyFile.path, andPath: testDir1.appendingPathComponent("unreadable_file").path)) |
| #endif |
| |
| XCTAssertTrue(fm.contentsEqual(atPath: testFile1URL.path, andPath: testFile1URL.path)) |
| XCTAssertFalse(fm.contentsEqual(atPath: testFile1URL.path, andPath: testFile2URL.path)) |
| XCTAssertFalse(fm.contentsEqual(atPath: testFile3URL.path, andPath: testFile4URL.path)) |
| XCTAssertFalse(fm.contentsEqual(atPath: symlink, andPath: testFile1URL.path)) |
| |
| XCTAssertTrue(fm.contentsEqual(atPath: testDir1.path, andPath: testDir1.path)) |
| XCTAssertTrue(fm.contentsEqual(atPath: testDir2.path, andPath: testDir3.path)) |
| XCTAssertFalse(fm.contentsEqual(atPath: testDir1.path, andPath: testDir2.path)) |
| |
| // Copy everything in testDir1 to testDir2 to make them equal |
| do { |
| for entry in try fm.subpathsOfDirectory(atPath: testDir1.path) { |
| // Skip entries that already exist |
| if entry == "bar2" || entry == "unreadable_file" { |
| continue |
| } |
| let srcPath = testDir1.appendingPathComponent(entry).path |
| let dstPath = testDir2.appendingPathComponent(entry).path |
| if let attrs = try? fm.attributesOfItem(atPath: srcPath), |
| let fileType = attrs[.type] as? FileAttributeType, fileType == .typeDirectory { |
| try fm.createDirectory(atPath: dstPath, withIntermediateDirectories: false, attributes: nil) |
| } else { |
| try fm.copyItem(atPath: srcPath, toPath: dstPath) |
| } |
| } |
| } catch { |
| XCTFail("Failed to copy \(testDir1.path) to \(testDir2.path), \(error)") |
| return |
| } |
| // This will still fail due to unreadable files and a file in testDir2 not in testDir1 |
| XCTAssertFalse(fm.contentsEqual(atPath: testDir1.path, andPath: testDir2.path)) |
| do { |
| try fm.copyItem(atPath: testDir2.appendingPathComponent("foo2").path, toPath: testDir1.appendingPathComponent("foo2").path) |
| try fm.removeItem(atPath: testDir1.appendingPathComponent("unreadable_file").path) |
| } catch { |
| XCTFail(String(describing: error)) |
| return |
| } |
| XCTAssertTrue(fm.contentsEqual(atPath: testDir1.path, andPath: testDir2.path)) |
| |
| let dataFile1 = testDir1.appendingPathComponent("dataFile") |
| let dataFile2 = testDir2.appendingPathComponent("dataFile") |
| do { |
| try Data(count: 100_000).write(to: dataFile1) |
| try fm.copyItem(atPath: dataFile1.path, toPath: dataFile2.path) |
| } catch { |
| XCTFail("Could not create test data files: \(error)") |
| return |
| } |
| XCTAssertTrue(fm.contentsEqual(atPath: dataFile1.path, andPath: dataFile2.path)) |
| XCTAssertTrue(fm.contentsEqual(atPath: testDir1.path, andPath: testDir2.path)) |
| var data = Data(count: 100_000) |
| data[99_999] = 1 |
| try? data.write(to: dataFile1) |
| XCTAssertFalse(fm.contentsEqual(atPath: dataFile1.path, andPath: dataFile2.path)) |
| XCTAssertFalse(fm.contentsEqual(atPath: testDir1.path, andPath: testDir2.path)) |
| } |
| |
| func test_copyItemsPermissions() throws { |
| let fm = FileManager.default |
| let tmpDir = fm.temporaryDirectory.appendingPathComponent("test_copyItemsPermissions") |
| try fm.createDirectory(at: tmpDir, withIntermediateDirectories: true) |
| defer { try? fm.removeItem(atPath: tmpDir.path) } |
| |
| let srcFile = tmpDir.appendingPathComponent("file1.txt") |
| let destFile = tmpDir.appendingPathComponent("file2.txt") |
| |
| let source = "This is the source file" |
| try? fm.removeItem(at: srcFile) |
| try source.write(toFile: srcFile.path, atomically: false, encoding: .utf8) |
| |
| func testCopy() throws { |
| try? fm.removeItem(at: destFile) |
| try fm.copyItem(at: srcFile, to: destFile) |
| let copy = try String(contentsOf: destFile) |
| XCTAssertEqual(source, copy) |
| if let srcPerms = (try fm.attributesOfItem(atPath: srcFile.path)[.posixPermissions] as? NSNumber)?.intValue, |
| let destPerms = (try fm.attributesOfItem(atPath: destFile.path)[.posixPermissions] as? NSNumber)?.intValue { |
| XCTAssertEqual(srcPerms, destPerms) |
| } else { |
| XCTFail("Cant get file permissions") |
| } |
| } |
| |
| try testCopy() |
| |
| try fm.setAttributes([ .posixPermissions: 0o417], ofItemAtPath: srcFile.path) |
| try testCopy() |
| |
| try fm.setAttributes([ .posixPermissions: 0o400], ofItemAtPath: srcFile.path) |
| try testCopy() |
| |
| try fm.setAttributes([ .posixPermissions: 0o700], ofItemAtPath: srcFile.path) |
| try testCopy() |
| |
| try fm.setAttributes([ .posixPermissions: 0o707], ofItemAtPath: srcFile.path) |
| try testCopy() |
| |
| try fm.setAttributes([ .posixPermissions: 0o411], ofItemAtPath: srcFile.path) |
| try testCopy() |
| } |
| |
| #if !DEPLOYMENT_RUNTIME_OBJC && !os(Android) // XDG tests require swift-corelibs-foundation |
| |
| #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT // These are white box tests for the internals of XDG parsing: |
| func test_xdgStopgapsCoverAllConstants() { |
| let stopgaps = _XDGUserDirectory.stopgapDefaultDirectoryURLs |
| for directory in _XDGUserDirectory.allDirectories { |
| XCTAssertNotNil(stopgaps[directory]) |
| } |
| } |
| |
| func test_parseXDGConfiguration() { |
| let home = URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true) |
| |
| let assertConfigurationProduces = { (configuration: String, paths: [_XDGUserDirectory: String]) in |
| XCTAssertEqual(_XDGUserDirectory.userDirectories(fromConfiguration: configuration).mapValues({ $0.absoluteURL.path }), |
| paths.mapValues({ URL(fileURLWithPath: $0, isDirectory: true, relativeTo: home).absoluteURL.path })) |
| } |
| |
| assertConfigurationProduces("", [:]) |
| |
| // Test partial configuration and paths relative to home. |
| assertConfigurationProduces( |
| """ |
| DESKTOP=/xdg_test/Desktop |
| MUSIC=/xdg_test/Music |
| PICTURES=Pictures |
| """, [ .desktop: "/xdg_test/Desktop", |
| .music: "/xdg_test/Music", |
| .pictures: "Pictures" ]) |
| |
| // Test full configuration with XDG_…_DIR syntax, duplicate keys and varying indentation |
| // 'XDG_MUSIC_DIR' is duplicated, below. |
| assertConfigurationProduces( |
| """ |
| XDG_MUSIC_DIR=ShouldNotBeUsedUseTheOneBelowInstead |
| |
| XDG_DESKTOP_DIR=Desktop |
| XDG_DOWNLOAD_DIR=Download |
| XDG_PUBLICSHARE_DIR=Public |
| XDG_DOCUMENTS_DIR=Documents |
| XDG_MUSIC_DIR=Music |
| XDG_PICTURES_DIR=Pictures |
| XDG_VIDEOS_DIR=Videos |
| """, [ .desktop: "Desktop", |
| .download: "Download", |
| .publicShare: "Public", |
| .documents: "Documents", |
| .music: "Music", |
| .pictures: "Pictures", |
| .videos: "Videos" ]) |
| |
| // Same, without XDG…DIR. |
| assertConfigurationProduces( |
| """ |
| MUSIC=ShouldNotBeUsedUseTheOneBelowInstead |
| |
| DESKTOP=Desktop |
| DOWNLOAD=Download |
| PUBLICSHARE=Public |
| DOCUMENTS=Documents |
| MUSIC=Music |
| PICTURES=Pictures |
| VIDEOS=Videos |
| """, [ .desktop: "Desktop", |
| .download: "Download", |
| .publicShare: "Public", |
| .documents: "Documents", |
| .music: "Music", |
| .pictures: "Pictures", |
| .videos: "Videos" ]) |
| |
| assertConfigurationProduces( |
| """ |
| DESKTOP=/home/Desktop |
| This configuration file has an invalid syntax. |
| """, [:]) |
| } |
| |
| func test_xdgURLSelection() { |
| let home = URL(fileURLWithPath: NSHomeDirectory(), isDirectory: true) |
| |
| let configuration = _XDGUserDirectory.userDirectories(fromConfiguration: |
| """ |
| DESKTOP=UserDesktop |
| """ |
| ) |
| |
| let osDefaults = _XDGUserDirectory.userDirectories(fromConfiguration: |
| """ |
| DESKTOP=SystemDesktop |
| PUBLICSHARE=SystemPublicShare |
| """ |
| ) |
| |
| let stopgaps = _XDGUserDirectory.userDirectories(fromConfiguration: |
| """ |
| DESKTOP=StopgapDesktop |
| DOWNLOAD=StopgapDownload |
| PUBLICSHARE=StopgapPublicShare |
| DOCUMENTS=StopgapDocuments |
| MUSIC=StopgapMusic |
| PICTURES=StopgapPictures |
| VIDEOS=StopgapVideos |
| """ |
| ) |
| |
| let assertSameAbsolutePath = { (lhs: URL, rhs: URL) in |
| XCTAssertEqual(lhs.absoluteURL.path, rhs.absoluteURL.path) |
| } |
| |
| assertSameAbsolutePath(_XDGUserDirectory.desktop.url(userConfiguration: configuration, osDefaultConfiguration: osDefaults, stopgaps: stopgaps), home.appendingPathComponent("UserDesktop")) |
| assertSameAbsolutePath(_XDGUserDirectory.publicShare.url(userConfiguration: configuration, osDefaultConfiguration: osDefaults, stopgaps: stopgaps), home.appendingPathComponent("SystemPublicShare")) |
| assertSameAbsolutePath(_XDGUserDirectory.music.url(userConfiguration: configuration, osDefaultConfiguration: osDefaults, stopgaps: stopgaps), home.appendingPathComponent("StopgapMusic")) |
| } |
| #endif // NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT |
| |
| // This test below is a black box test, and does not require @testable import. |
| |
| #if !os(Android) |
| func printPathByRunningHelper(withConfiguration config: String, method: String, identifier: String) throws -> String { |
| let uuid = UUID().uuidString |
| let path = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("org.swift.Foundation.XDGTestHelper").appendingPathComponent(uuid) |
| try FileManager.default.createDirectory(at: path, withIntermediateDirectories: true) |
| |
| let configFilePath = path.appendingPathComponent("user-dirs.dirs") |
| try config.write(to: configFilePath, atomically: true, encoding: .utf8) |
| defer { |
| try? FileManager.default.removeItem(at: path) |
| } |
| |
| var environment = [ "XDG_CONFIG_HOME": path.path, |
| "_NSFileManagerUseXDGPathsForDirectoryDomains": "YES" ] |
| |
| // Copy all LD_* and DYLD_* variables over, in case we're running with altered paths (e.g. from ninja test on Linux) |
| for entry in ProcessInfo.processInfo.environment.lazy.filter({ $0.key.hasPrefix("DYLD_") || $0.key.hasPrefix("LD_") }) { |
| environment[entry.key] = entry.value |
| } |
| |
| let helper = xdgTestHelperURL() |
| let (stdout, _) = try runTask([ helper.path, "--nspathfor", method, identifier ], |
| environment: environment) |
| |
| return stdout.trimmingCharacters(in: CharacterSet.newlines) |
| } |
| |
| func assertFetchingPath(withConfiguration config: String, identifier: String, yields path: String) { |
| for method in [ "NSSearchPath", "FileManagerDotURLFor", "FileManagerDotURLsFor" ] { |
| do { |
| let found = try printPathByRunningHelper(withConfiguration: config, method: method, identifier: identifier) |
| XCTAssertEqual(found, path) |
| } catch let error { |
| XCTFail("Failed with method \(method), configuration \(config), identifier \(identifier), equal to \(path), error \(error)") |
| } |
| } |
| } |
| |
| func test_fetchXDGPathsFromHelper() { |
| let prefix = NSHomeDirectory() + "/_Foundation_Test_" |
| |
| let configuration = """ |
| DESKTOP=\(prefix)/Desktop |
| DOWNLOAD=\(prefix)/Download |
| PUBLICSHARE=\(prefix)/PublicShare |
| DOCUMENTS=\(prefix)/Documents |
| MUSIC=\(prefix)/Music |
| PICTURES=\(prefix)/Pictures |
| VIDEOS=\(prefix)/Videos |
| """ |
| |
| assertFetchingPath(withConfiguration: configuration, identifier: "desktop", yields: "\(prefix)/Desktop") |
| assertFetchingPath(withConfiguration: configuration, identifier: "download", yields: "\(prefix)/Download") |
| assertFetchingPath(withConfiguration: configuration, identifier: "publicShare", yields: "\(prefix)/PublicShare") |
| assertFetchingPath(withConfiguration: configuration, identifier: "documents", yields: "\(prefix)/Documents") |
| assertFetchingPath(withConfiguration: configuration, identifier: "music", yields: "\(prefix)/Music") |
| assertFetchingPath(withConfiguration: configuration, identifier: "pictures", yields: "\(prefix)/Pictures") |
| assertFetchingPath(withConfiguration: configuration, identifier: "videos", yields: "\(prefix)/Videos") |
| } |
| #endif // !os(Android) |
| #endif // !DEPLOYMENT_RUNTIME_OBJC |
| |
| func test_emptyFilename() { |
| |
| // Some of these tests will throw an NSException on Darwin which would be normally be |
| // modelled by a fatalError() or other hard failure, however since most of these functions |
| // are thorwable, an NSError is thrown instead which is more useful. |
| let fm = FileManager.default |
| |
| XCTAssertNil(fm.homeDirectory(forUser: "")) |
| XCTAssertNil(NSHomeDirectoryForUser("")) |
| |
| XCTAssertThrowsError(try fm.contentsOfDirectory(atPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| |
| XCTAssertNil(fm.enumerator(atPath: "")) |
| XCTAssertNil(fm.subpaths(atPath: "")) |
| XCTAssertThrowsError(try fm.subpathsOfDirectory(atPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| |
| XCTAssertThrowsError(try fm.createDirectory(atPath: "", withIntermediateDirectories: true)) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertFalse(fm.createFile(atPath: "", contents: Data())) |
| XCTAssertThrowsError(try fm.removeItem(atPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| |
| XCTAssertThrowsError(try fm.copyItem(atPath: "", toPath: "/tmp/t")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertThrowsError(try fm.copyItem(atPath: "", toPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertThrowsError(try fm.copyItem(atPath: "/tmp/t", toPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadNoSuchFile) |
| } |
| |
| XCTAssertThrowsError(try fm.moveItem(atPath: "", toPath: "/tmp/t")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertThrowsError(try fm.moveItem(atPath: "", toPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertThrowsError(try fm.moveItem(atPath: "/tmp/t", toPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| |
| XCTAssertThrowsError(try fm.linkItem(atPath: "", toPath: "/tmp/t")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertThrowsError(try fm.linkItem(atPath: "", toPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertThrowsError(try fm.linkItem(atPath: "/tmp/t", toPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadNoSuchFile) |
| } |
| |
| XCTAssertThrowsError(try fm.createSymbolicLink(atPath: "", withDestinationPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertThrowsError(try fm.createSymbolicLink(atPath: "", withDestinationPath: "/tmp/t")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertThrowsError(try fm.createSymbolicLink(atPath: "/tmp/t", withDestinationPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| |
| XCTAssertThrowsError(try fm.destinationOfSymbolicLink(atPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertFalse(fm.fileExists(atPath: "")) |
| XCTAssertFalse(fm.fileExists(atPath: "", isDirectory: nil)) |
| XCTAssertFalse(fm.isReadableFile(atPath: "")) |
| XCTAssertFalse(fm.isWritableFile(atPath: "")) |
| XCTAssertFalse(fm.isExecutableFile(atPath: "")) |
| XCTAssertTrue(fm.isDeletableFile(atPath: "")) |
| |
| XCTAssertThrowsError(try fm.attributesOfItem(atPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertThrowsError(try fm.attributesOfFileSystem(forPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| XCTAssertThrowsError(try fm.setAttributes([:], ofItemAtPath: "")) { |
| let code = CocoaError.Code(rawValue: ($0 as? NSError)!.code) |
| XCTAssertEqual(code, .fileReadInvalidFileName) |
| } |
| |
| XCTAssertNil(fm.contents(atPath: "")) |
| XCTAssertFalse(fm.contentsEqual(atPath: "", andPath: "")) |
| XCTAssertFalse(fm.contentsEqual(atPath: "/tmp/t", andPath: "")) |
| XCTAssertFalse(fm.contentsEqual(atPath: "", andPath: "/tmp/t")) |
| |
| //_ = fm.fileSystemRepresentation(withPath: "") // NSException |
| XCTAssertEqual(fm.string(withFileSystemRepresentation: UnsafePointer(bitPattern: 1)!, length: 0), "") |
| |
| XCTAssertFalse(fm.changeCurrentDirectoryPath("")) |
| XCTAssertNotEqual(fm.currentDirectoryPath, "") |
| |
| // Not Implemented - XCTAssertNil(fm.componentsToDisplay(forPath: "")) |
| // Not Implemented - XCTAssertEqual(fm.displayName(atPath: ""), "") |
| } |
| |
| func test_getRelationship() throws { |
| /* a/ |
| a/b |
| a/bb |
| c -> symlink to a/b |
| d */ |
| |
| let a = writableTestDirectoryURL.appendingPathComponent("a") |
| let a_b = a.appendingPathComponent("b") |
| let a_bb = a.appendingPathComponent("bb") |
| let c = writableTestDirectoryURL.appendingPathComponent("c") |
| let a_b_d = a_b.appendingPathComponent("d") |
| |
| let fm = FileManager.default |
| try fm.createDirectory(at: a, withIntermediateDirectories: true) |
| try fm.createDirectory(at: a_b, withIntermediateDirectories: true) |
| try Data().write(to: a_bb) |
| try Data().write(to: c) |
| try fm.createSymbolicLink(at: a_b_d, withDestinationURL: a) |
| |
| var relationship: FileManager.URLRelationship = .other |
| |
| try fm.getRelationship(&relationship, ofDirectoryAt: writableTestDirectoryURL, toItemAt: a) |
| XCTAssertEqual(relationship, .contains) |
| |
| try fm.getRelationship(&relationship, ofDirectoryAt: a, toItemAt: a_b) |
| XCTAssertEqual(relationship, .contains) |
| |
| // The path of one is a prefix to the other, but lacks the directory separator. |
| try fm.getRelationship(&relationship, ofDirectoryAt: a_b, toItemAt: a_bb) |
| XCTAssertEqual(relationship, .other) |
| |
| try fm.getRelationship(&relationship, ofDirectoryAt: a_b, toItemAt: c) |
| XCTAssertEqual(relationship, .other) |
| |
| try fm.getRelationship(&relationship, ofDirectoryAt: a_b_d, toItemAt: a) |
| XCTAssertEqual(relationship, .same) |
| } |
| |
| func test_displayNames() throws { |
| /* a/ |
| a/Test.localized (with a ./.localized/ subdirectory and strings file); |
| a/Test.localized/b |
| */ |
| |
| let a = writableTestDirectoryURL.appendingPathComponent("a") |
| let a_Test = a.appendingPathComponent("Test.localized") |
| let a_Test_dotLocalized = a_Test.appendingPathComponent(".localized") |
| let a_Test_dotLocalized_enStrings = a_Test_dotLocalized.appendingPathComponent("en.strings") |
| let a_Test_dotLocalized_itStrings = a_Test_dotLocalized.appendingPathComponent("it.strings") |
| let a_Test_b = a_Test.appendingPathComponent("b") |
| |
| let fm = FileManager.default |
| try fm.createDirectory(at: a, withIntermediateDirectories: true) |
| try fm.createDirectory(at: a_Test, withIntermediateDirectories: true) |
| try fm.createDirectory(at: a_Test_dotLocalized, withIntermediateDirectories: true) |
| try Data("\"Test\" = \"Test\";".utf8).write(to: a_Test_dotLocalized_enStrings) |
| try Data("\"Test\" = \"Prova\";".utf8).write(to: a_Test_dotLocalized_itStrings) |
| try fm.createDirectory(at: a_Test_b, withIntermediateDirectories: true) |
| |
| XCTAssertEqual(fm.displayName(atPath: a.path), "a") |
| |
| #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT |
| fm._overridingDisplayNameLanguages(with: ["en", "es", "it"]) { |
| XCTAssertEqual(fm.displayName(atPath: a_Test.path), "Test") |
| } |
| fm._overridingDisplayNameLanguages(with: ["it", "en", "es"]) { |
| XCTAssertEqual(fm.displayName(atPath: a_Test.path), "Prova") |
| } |
| fm._overridingDisplayNameLanguages(with: ["es", "it", "en"]) { |
| XCTAssertEqual(fm.displayName(atPath: a_Test.path), "Prova") |
| } |
| #endif |
| |
| do { |
| let components = try XCTUnwrap(fm.componentsToDisplay(forPath: a.path)) |
| XCTAssertGreaterThanOrEqual(components.count, 2) |
| XCTAssertEqual(components.last, "a") |
| } |
| |
| do { |
| #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT |
| let components = try fm._overridingDisplayNameLanguages(with: ["it"]) { |
| return try XCTUnwrap(fm.componentsToDisplay(forPath: a_Test.path)) |
| } |
| #else |
| let components = try XCTUnwrap(fm.componentsToDisplay(forPath: a_Test.path)) |
| #endif |
| |
| XCTAssertGreaterThanOrEqual(components.count, 3) |
| XCTAssertEqual(components[components.count - 2], "a") |
| |
| #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT |
| XCTAssertEqual(components.last, "Prova") |
| #endif |
| } |
| |
| do { |
| #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT |
| let components = try fm._overridingDisplayNameLanguages(with: ["en"]) { |
| return try XCTUnwrap(fm.componentsToDisplay(forPath: a_Test_b.path)) |
| } |
| #else |
| let components = try XCTUnwrap(fm.componentsToDisplay(forPath: a_Test_b.path)) |
| #endif |
| |
| XCTAssertGreaterThanOrEqual(components.count, 4) |
| XCTAssertEqual(components[components.count - 3], "a") |
| |
| #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT |
| XCTAssertEqual(components[components.count - 2], "Test") |
| #endif |
| |
| XCTAssertEqual(components.last, "b") |
| } |
| |
| } |
| |
| func test_getItemReplacementDirectory() throws { |
| try FileManager.default.createDirectory(at: writableTestDirectoryURL, withIntermediateDirectories: true) |
| let a = writableTestDirectoryURL.appendingPathComponent("a") |
| try Data().write(to: a) |
| |
| let whereAt = try FileManager.default.url(for: .itemReplacementDirectory, in: .userDomainMask, appropriateFor: a, create: false) |
| // Either this is in the temporary directory, or this is on the same filesystem as 'a' (at writableTestDirectoryURL). |
| if whereAt.deletingLastPathComponent() == writableTestDirectoryURL { |
| XCTAssertEqual(whereAt.deletingLastPathComponent(), writableTestDirectoryURL) |
| } else { |
| var relationship: FileManager.URLRelationship = .other |
| try FileManager.default.getRelationship(&relationship, ofDirectoryAt: URL(fileURLWithPath: NSTemporaryDirectory()), toItemAt: whereAt.deletingLastPathComponent()) |
| XCTAssertEqual(relationship, .contains) |
| } |
| |
| // To avoid races, Darwin always creates the directory even if create: false. Check this is the case. |
| XCTAssertNotNil(try? FileManager.default.attributesOfItem(atPath: whereAt.path)) |
| try? FileManager.default.removeItem(at: whereAt) |
| } |
| |
| func test_replacement() throws { |
| let fm = FileManager.default |
| let a = writableTestDirectoryURL.appendingPathComponent("a") |
| |
| let initialData = Data("INITIAL".utf8) |
| let finalData = Data("FINAL".utf8) |
| var temporaryDirectory: URL! |
| var b: URL! |
| |
| let initialFileName = "INITIAL" |
| let finalFileName = "FINAL" |
| |
| func setUpReplacement(aIsDirectory: Bool, bIsDirectory: Bool) throws { |
| try fm.createDirectory(at: writableTestDirectoryURL, withIntermediateDirectories: true) |
| if aIsDirectory { |
| try fm.createDirectory(at: a, withIntermediateDirectories: true) |
| try Data().write(to: a.appendingPathComponent(initialFileName)) |
| } else { |
| try initialData.write(to: a) |
| } |
| |
| temporaryDirectory = try fm.url(for: .itemReplacementDirectory, in: .userDomainMask, appropriateFor: a, create: true) |
| |
| if bIsDirectory { |
| b = temporaryDirectory.appendingPathComponent("b") |
| try fm.createDirectory(at: b, withIntermediateDirectories: true) |
| try Data().write(to: b.appendingPathComponent(finalFileName)) |
| } else { |
| b = temporaryDirectory.appendingPathComponent("b") |
| try finalData.write(to: b) |
| } |
| } |
| |
| func tearDownReplacement() throws { |
| try? fm.removeItem(at: a) |
| try? fm.removeItem(at: writableTestDirectoryURL.appendingPathComponent("c")) |
| try? fm.removeItem(at: temporaryDirectory) |
| } |
| |
| var stderr = FileHandle.standardError |
| |
| func testReplaceMethod(invokedBy replace: (URL, URL, String?, FileManager.ItemReplacementOptions) throws -> URL?) throws { |
| func runSingleTest(aIsDirectory: Bool, bIsDirectory: Bool, options: FileManager.ItemReplacementOptions = []) throws { |
| print("note: Testing with: a is directory? \(aIsDirectory), b is directory? \(bIsDirectory), using new metadata only? \(options.contains(.usingNewMetadataOnly)), without deleting backup item? \(options.contains(.withoutDeletingBackupItem))", to: &stderr) |
| try setUpReplacement(aIsDirectory: aIsDirectory, bIsDirectory: bIsDirectory) |
| |
| let initialAttributes = options.contains(.usingNewMetadataOnly) ? try fm.attributesOfItem(atPath: b.path) : try fm.attributesOfItem(atPath: a.path) |
| |
| // Do the thing. |
| let result = try replace(a, b, "c", options) |
| |
| let c = writableTestDirectoryURL.appendingPathComponent("c") |
| let cAttributes = try? fm.attributesOfItem(atPath: c.path) |
| if options.contains(.withoutDeletingBackupItem) { |
| XCTAssertNotNil(cAttributes) |
| |
| if aIsDirectory { |
| XCTAssertNotNil(try? fm.attributesOfItem(atPath: c.appendingPathComponent(initialFileName).path)) |
| XCTAssertNil(try? fm.attributesOfItem(atPath: c.appendingPathComponent(finalFileName).path)) |
| } else { |
| XCTAssertEqual(try? Data(contentsOf: c), initialData) |
| } |
| |
| // Remove the backup manually. |
| try? fm.removeItem(at: c) |
| } else { |
| XCTAssertNil(cAttributes) |
| } |
| |
| let newA = try XCTUnwrap(result) |
| |
| let finalAttributes = try fm.attributesOfItem(atPath: newA.path) |
| XCTAssertEqual(initialAttributes[.creationDate] as? AnyHashable, finalAttributes[.creationDate] as? AnyHashable) |
| XCTAssertEqual(initialAttributes[.posixPermissions] as? AnyHashable, finalAttributes[.posixPermissions] as? AnyHashable) |
| |
| if bIsDirectory { |
| // Ensure we have execute permission, which can happen if .…newMetadataOnly isn't used, and we replace a file with a directory. (That's why we check attributes first.) |
| try? fm.setAttributes([.posixPermissions: 0o777], ofItemAtPath: newA.path) |
| XCTAssertNil(try? fm.attributesOfItem(atPath: newA.appendingPathComponent(initialFileName).path)) |
| XCTAssertNotNil(try? fm.attributesOfItem(atPath: newA.appendingPathComponent(finalFileName).path)) |
| } else { |
| XCTAssertEqual(try? Data(contentsOf: newA), finalData) |
| } |
| |
| try tearDownReplacement() |
| } |
| |
| try runSingleTest(aIsDirectory: false, bIsDirectory: false) |
| try runSingleTest(aIsDirectory: false, bIsDirectory: false, options: .withoutDeletingBackupItem) |
| try runSingleTest(aIsDirectory: false, bIsDirectory: false, options: .usingNewMetadataOnly) |
| try runSingleTest(aIsDirectory: false, bIsDirectory: false, options: [.withoutDeletingBackupItem, .usingNewMetadataOnly]) |
| try runSingleTest(aIsDirectory: true, bIsDirectory: true) |
| try runSingleTest(aIsDirectory: true, bIsDirectory: true, options: .withoutDeletingBackupItem) |
| try runSingleTest(aIsDirectory: true, bIsDirectory: true, options: .usingNewMetadataOnly) |
| try runSingleTest(aIsDirectory: true, bIsDirectory: true, options: [.withoutDeletingBackupItem, .usingNewMetadataOnly]) |
| try runSingleTest(aIsDirectory: false, bIsDirectory: true) |
| try runSingleTest(aIsDirectory: false, bIsDirectory: true, options: .withoutDeletingBackupItem) |
| try runSingleTest(aIsDirectory: false, bIsDirectory: true, options: .usingNewMetadataOnly) |
| try runSingleTest(aIsDirectory: false, bIsDirectory: true, options: [.withoutDeletingBackupItem, .usingNewMetadataOnly]) |
| try runSingleTest(aIsDirectory: true, bIsDirectory: false) |
| try runSingleTest(aIsDirectory: true, bIsDirectory: false, options: .withoutDeletingBackupItem) |
| try runSingleTest(aIsDirectory: true, bIsDirectory: false, options: .usingNewMetadataOnly) |
| try runSingleTest(aIsDirectory: true, bIsDirectory: false, options: [.withoutDeletingBackupItem, .usingNewMetadataOnly]) |
| } |
| |
| print("Testing Darwin Foundation compatible replace", to: &stderr) |
| try testReplaceMethod { (a, b, backupItemName, options) -> URL? in |
| try fm.replaceItemAt(a, withItemAt: b, backupItemName: backupItemName, options: options) |
| } |
| |
| #if !DARWIN_COMPATIBILITY_TESTS |
| print("note: Testing platform-specific replace implementation.", to: &stderr) |
| try testReplaceMethod { (a, b, backupItemName, options) -> URL? in |
| try fm.replaceItem(at: a, withItemAt: b, backupItemName: backupItemName, options: options) |
| } |
| #endif |
| |
| #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT |
| print("note: Testing cross-platform replace implementation.", to: &stderr) |
| try testReplaceMethod { (a, b, backupItemName, options) -> URL? in |
| try fm._replaceItem(at: a, withItemAt: b, backupItemName: backupItemName, options: options, allowPlatformSpecificSyscalls: false) |
| } |
| #endif |
| } |
| |
| // ----- |
| |
| var writableTestDirectoryURL: URL! |
| |
| override func setUp() { |
| super.setUp() |
| |
| let pid = ProcessInfo.processInfo.processIdentifier |
| writableTestDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("org.swift.TestFoundation.TestFileManager.\(pid)") |
| } |
| |
| override func tearDown() { |
| if let directoryURL = writableTestDirectoryURL, |
| (try? FileManager.default.attributesOfItem(atPath: directoryURL.path)) != nil { |
| do { |
| try FileManager.default.removeItem(at: directoryURL) |
| } catch { |
| NSLog("Could not remove test directory at URL \(directoryURL): \(error)") |
| } |
| } |
| |
| super.tearDown() |
| } |
| |
| static var allTests: [(String, (TestFileManager) -> () throws -> Void)] { |
| var tests: [(String, (TestFileManager) -> () throws -> Void)] = [ |
| ("test_createDirectory", test_createDirectory ), |
| ("test_createFile", test_createFile ), |
| ("test_moveFile", test_moveFile), |
| ("test_fileSystemRepresentation", test_fileSystemRepresentation), |
| ("test_fileExists", test_fileExists), |
| ("test_isReadableFile", test_isReadableFile), |
| ("test_isWritableFile", test_isWritableFile), |
| ("test_isExecutableFile", test_isExecutableFile), |
| ("test_isDeletableFile", test_isDeletableFile), |
| ("test_fileAttributes", test_fileAttributes), |
| ("test_fileSystemAttributes", test_fileSystemAttributes), |
| ("test_setFileAttributes", test_setFileAttributes), |
| ("test_directoryEnumerator", test_directoryEnumerator), |
| ("test_pathEnumerator",test_pathEnumerator), |
| ("test_contentsOfDirectoryAtPath", test_contentsOfDirectoryAtPath), |
| ("test_subpathsOfDirectoryAtPath", test_subpathsOfDirectoryAtPath), |
| ("test_copyItemAtPathToPath", test_copyItemAtPathToPath), |
| ("test_linkItemAtPathToPath", testExpectedToFailOnAndroid(test_linkItemAtPathToPath, "Android doesn't allow hard links")), |
| ("test_homedirectoryForUser", test_homedirectoryForUser), |
| ("test_temporaryDirectoryForUser", test_temporaryDirectoryForUser), |
| ("test_creatingDirectoryWithShortIntermediatePath", test_creatingDirectoryWithShortIntermediatePath), |
| ("test_mountedVolumeURLs", test_mountedVolumeURLs), |
| ("test_copyItemsPermissions", test_copyItemsPermissions), |
| ("test_emptyFilename", test_emptyFilename), |
| ("test_getRelationship", test_getRelationship), |
| ("test_displayNames", test_displayNames), |
| ("test_getItemReplacementDirectory", test_getItemReplacementDirectory), |
| ("test_contentsEqual", test_contentsEqual), |
| /* ⚠️ */ ("test_replacement", testExpectedToFail(test_replacement, |
| /* ⚠️ */ "<https://bugs.swift.org/browse/SR-10819> Re-enable Foundation test TestFileManager.test_replacement")), |
| ] |
| |
| #if !DEPLOYMENT_RUNTIME_OBJC && NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT && !os(Android) |
| tests.append(contentsOf: [ |
| ("test_xdgStopgapsCoverAllConstants", test_xdgStopgapsCoverAllConstants), |
| ("test_parseXDGConfiguration", test_parseXDGConfiguration), |
| ("test_xdgURLSelection", test_xdgURLSelection), |
| ]) |
| #endif |
| |
| #if !DEPLOYMENT_RUNTIME_OBJC && !os(Android) && !os(Windows) |
| tests.append(contentsOf: [ |
| ("test_fetchXDGPathsFromHelper", test_fetchXDGPathsFromHelper), |
| ]) |
| #endif |
| |
| return tests |
| } |
| } |