From 784b072fafa18992d76ebf7807902dbb9dc926e6 Mon Sep 17 00:00:00 2001 From: Rui Mendes Date: Thu, 12 Feb 2026 11:46:58 +0000 Subject: [PATCH 1/7] fix: inconsistent error codes when missing file --- IONFilesystemLib/IONFILEManager.swift | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/IONFilesystemLib/IONFILEManager.swift b/IONFilesystemLib/IONFILEManager.swift index 71a2e65..feac501 100644 --- a/IONFilesystemLib/IONFILEManager.swift +++ b/IONFilesystemLib/IONFILEManager.swift @@ -27,6 +27,9 @@ extension IONFILEManager: IONFILEDirectoryManager { public func removeDirectory(atURL pathURL: URL, includeIntermediateDirectories: Bool) throws { try withSecurityScopedAccess(to: pathURL) { + guard fileManager.fileExists(atPath: pathURL.urlPath) else { + throw IONFILEFileManagerError.fileNotFound(atPath: pathURL.urlPath) + } if !includeIntermediateDirectories { let directoryContents = try listDirectory(atURL: pathURL) if !directoryContents.isEmpty { @@ -40,7 +43,10 @@ extension IONFILEManager: IONFILEDirectoryManager { public func listDirectory(atURL pathURL: URL) throws -> [URL] { try withSecurityScopedAccess(to: pathURL) { - try fileManager.contentsOfDirectory(at: pathURL, includingPropertiesForKeys: nil) + guard fileManager.fileExists(atPath: pathURL.urlPath) else { + throw IONFILEFileManagerError.fileNotFound(atPath: pathURL.urlPath) + } + return try fileManager.contentsOfDirectory(at: pathURL, includingPropertiesForKeys: nil) } } } @@ -56,6 +62,9 @@ extension IONFILEManager: IONFILEFileManager { public func readEntireFile(atURL fileURL: URL, withEncoding encoding: IONFILEEncoding, andOffset offset: Int, andLength length: Int) throws -> IONFILEEncodingValueMapper { try withSecurityScopedAccess(to: fileURL) { + guard fileManager.fileExists(atPath: fileURL.urlPath) else { + throw IONFILEFileManagerError.fileNotFound(atPath: fileURL.urlPath) + } let result: IONFILEEncodingValueMapper if (offset > 0 || length > 0) { result = try readPartialFile(fileURL, encoding, offset, length) @@ -75,7 +84,10 @@ extension IONFILEManager: IONFILEFileManager { public func readFileInChunks(atURL fileURL: URL, withEncoding encoding: IONFILEEncoding, andChunkSize chunkSize: Int, andOffset offset: Int, andLength length: Int) throws -> IONFILEChunkPublisher { try withSecurityScopedAccess(to: fileURL) { - .init(fileURL, chunkSize, encoding, offset, length) + guard fileManager.fileExists(atPath: fileURL.urlPath) else { + throw IONFILEFileManagerError.fileNotFound(atPath: fileURL.urlPath) + } + return .init(fileURL, chunkSize, encoding, offset, length) } } @@ -147,6 +159,9 @@ extension IONFILEManager: IONFILEFileManager { public func getItemAttributes(atURL url: URL) throws -> IONFILEItemAttributeModel { try withSecurityScopedAccess(to: url) { + guard fileManager.fileExists(atPath: url.urlPath) else { + throw IONFILEFileManagerError.fileNotFound(atPath: url.urlPath) + } let attributesDictionary = try fileManager.attributesOfItem(atPath: url.urlPath) return .create(from: attributesDictionary) } @@ -154,6 +169,9 @@ extension IONFILEManager: IONFILEFileManager { public func renameItem(fromURL originURL: URL, toURL destinationURL: URL) throws { try withSecurityScopedAccess(to: originURL) { + guard fileManager.fileExists(atPath: originURL.urlPath) else { + throw IONFILEFileManagerError.fileNotFound(atPath: originURL.urlPath) + } try withSecurityScopedAccess(to: destinationURL) { guard try shouldPerformDualPathOperation(fromURL: originURL, toURL: destinationURL) else { return @@ -165,6 +183,9 @@ extension IONFILEManager: IONFILEFileManager { public func copyItem(fromURL originURL: URL, toURL destinationURL: URL) throws { try withSecurityScopedAccess(to: originURL) { + guard fileManager.fileExists(atPath: originURL.urlPath) else { + throw IONFILEFileManagerError.fileNotFound(atPath: originURL.urlPath) + } try withSecurityScopedAccess(to: destinationURL) { guard try shouldPerformDualPathOperation(fromURL: originURL, toURL: destinationURL) else { return From 11e9073eeb5316f3035b80ab836f774b0abdcf40 Mon Sep 17 00:00:00 2001 From: Rui Mendes Date: Thu, 12 Feb 2026 13:00:56 +0000 Subject: [PATCH 2/7] update changelog and bump version --- CHANGELOG.md | 6 ++++++ IONFilesystemLib.xcodeproj/project.pbxproj | 12 ++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3473381..74b31d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 1.1.1 + +### Fix + +- Align iOS error codes with Android when file does not exist (return `OS-PLUG-FILE-0008` instead of `OS-PLUG-FILE-0013`) + ## 1.1.0 ### Features diff --git a/IONFilesystemLib.xcodeproj/project.pbxproj b/IONFilesystemLib.xcodeproj/project.pbxproj index fe270cb..d373699 100644 --- a/IONFilesystemLib.xcodeproj/project.pbxproj +++ b/IONFilesystemLib.xcodeproj/project.pbxproj @@ -333,7 +333,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.2; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.1.1; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -395,7 +395,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.2; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.1.1; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -429,7 +429,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.1.1; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; PRODUCT_BUNDLE_IDENTIFIER = io.ionic.libs.filesystem.FilesystemLib; @@ -464,7 +464,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.1.1; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; PRODUCT_BUNDLE_IDENTIFIER = io.ionic.libs.filesystem.FilesystemLib; @@ -484,7 +484,7 @@ CURRENT_PROJECT_VERSION = 4; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.0; - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.1.1; PRODUCT_BUNDLE_IDENTIFIER = io.ionic.libs.filesystem.FilesystemLibTests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -505,7 +505,7 @@ CURRENT_PROJECT_VERSION = 4; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.0; - MARKETING_VERSION = 1.1.0; + MARKETING_VERSION = 1.1.1; PRODUCT_BUNDLE_IDENTIFIER = io.ionic.libs.filesystem.FilesystemLibTests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; From 4b6b18302a308ab68f5dd357bd869a2e51704862 Mon Sep 17 00:00:00 2001 From: Rui Mendes Date: Thu, 12 Feb 2026 17:39:01 +0000 Subject: [PATCH 3/7] discard CHANGELOG updates --- CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74b31d6..3473381 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,3 @@ -## 1.1.1 - -### Fix - -- Align iOS error codes with Android when file does not exist (return `OS-PLUG-FILE-0008` instead of `OS-PLUG-FILE-0013`) - ## 1.1.0 ### Features From a4acaa58fa38ef7c49cc0163c98117a8c824b0d1 Mon Sep 17 00:00:00 2001 From: Rui Mendes Date: Thu, 12 Feb 2026 18:26:23 +0000 Subject: [PATCH 4/7] discard marketing version update --- IONFilesystemLib.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/IONFilesystemLib.xcodeproj/project.pbxproj b/IONFilesystemLib.xcodeproj/project.pbxproj index d373699..fe270cb 100644 --- a/IONFilesystemLib.xcodeproj/project.pbxproj +++ b/IONFilesystemLib.xcodeproj/project.pbxproj @@ -333,7 +333,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.2; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -395,7 +395,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.2; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; @@ -429,7 +429,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.0; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; PRODUCT_BUNDLE_IDENTIFIER = io.ionic.libs.filesystem.FilesystemLib; @@ -464,7 +464,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.0; MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; PRODUCT_BUNDLE_IDENTIFIER = io.ionic.libs.filesystem.FilesystemLib; @@ -484,7 +484,7 @@ CURRENT_PROJECT_VERSION = 4; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.0; - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = io.ionic.libs.filesystem.FilesystemLibTests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -505,7 +505,7 @@ CURRENT_PROJECT_VERSION = 4; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.0; - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = io.ionic.libs.filesystem.FilesystemLibTests; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; From 59bb780197726c1056420218c8c2468308bf791b Mon Sep 17 00:00:00 2001 From: OS-ruimoreiramendes Date: Fri, 13 Feb 2026 10:15:29 +0000 Subject: [PATCH 5/7] Update IONFilesystemLib/IONFILEManager.swift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: André Destro <254790+andredestro@users.noreply.github.com> --- IONFilesystemLib/IONFILEManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IONFilesystemLib/IONFILEManager.swift b/IONFilesystemLib/IONFILEManager.swift index feac501..c909be7 100644 --- a/IONFilesystemLib/IONFILEManager.swift +++ b/IONFilesystemLib/IONFILEManager.swift @@ -66,7 +66,7 @@ extension IONFILEManager: IONFILEFileManager { throw IONFILEFileManagerError.fileNotFound(atPath: fileURL.urlPath) } let result: IONFILEEncodingValueMapper - if (offset > 0 || length > 0) { + if offset > 0 || length > 0 { result = try readPartialFile(fileURL, encoding, offset, length) } else { switch encoding { From a4f7e0f07b9200261e2cf4e9abca9de6cebf01c5 Mon Sep 17 00:00:00 2001 From: OS-ruimoreiramendes Date: Fri, 13 Feb 2026 10:15:38 +0000 Subject: [PATCH 6/7] Update IONFilesystemLib/IONFILEManager.swift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: André Destro <254790+andredestro@users.noreply.github.com> --- IONFilesystemLib/IONFILEManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IONFilesystemLib/IONFILEManager.swift b/IONFilesystemLib/IONFILEManager.swift index c909be7..fe707de 100644 --- a/IONFilesystemLib/IONFILEManager.swift +++ b/IONFilesystemLib/IONFILEManager.swift @@ -292,7 +292,7 @@ private extension IONFILEManager { with: "/", options: .regularExpression ) - if (urlToReturn.absoluteString.contains(":///")) { + if urlToReturn.absoluteString.contains(":///") { // the regex may ommit a slash after ://, which is incorrect because it breaks in case of an absolute file path urlStringWithoutDuplicateSeparators = urlStringWithoutDuplicateSeparators.replacingOccurrences(of: "://", with: ":///") } From 3c71063e5c32d1a610b083acfccde550fe21f23b Mon Sep 17 00:00:00 2001 From: Rui Mendes Date: Fri, 13 Feb 2026 13:15:57 +0000 Subject: [PATCH 7/7] update automated tests --- .../IONFILEDirectoryManagerTests.swift | 42 ++++++++-- .../IONFILEFileManagerTests.swift | 80 ++++++++++++++++--- 2 files changed, 106 insertions(+), 16 deletions(-) diff --git a/IONFilesystemLibTests/IONFILEDirectoryManagerTests.swift b/IONFilesystemLibTests/IONFILEDirectoryManagerTests.swift index d35a267..8c29abf 100644 --- a/IONFilesystemLibTests/IONFILEDirectoryManagerTests.swift +++ b/IONFilesystemLibTests/IONFILEDirectoryManagerTests.swift @@ -69,7 +69,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase { // MARK: - 'removeDirectory' tests func test_removeDirectory_butFails_shouldReturnAnError() { let error = MockFileManagerError.deleteDirectoryError - createFileManager(with: error) + createFileManager(with: error, exclusions: []) let testDirectory = URL(filePath: "/test/directory") let shouldIncludeIntermediateDirectories = true @@ -81,10 +81,24 @@ final class IONFILEDirectoryManagerTests: XCTestCase { XCTAssertEqual($0 as? MockFileManagerError, error) } } + + func test_removeDirectory_butFails_shouldReturnFileNotFound() { + createFileManager(fileExists: false, exclusions: []) + let testDirectory = URL(filePath: "/test/directory") + let shouldIncludeIntermediateDirectories = true + + // When + XCTAssertThrowsError( + try sut.removeDirectory(atURL: testDirectory, includeIntermediateDirectories: shouldIncludeIntermediateDirectories) + ) { + // Then + XCTAssertEqual($0 as? IONFILEFileManagerError,.fileNotFound(atPath: testDirectory.urlPath)) + } + } func test_removeDirectory_includingIntermediateDirectories_shouldBeSuccessful() throws { // Given - let fileManager = createFileManager() + let fileManager = createFileManager(exclusions: []) let testDirectory = URL(filePath: "/test/directory") let shouldIncludeIntermediateDirectories = true @@ -97,7 +111,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase { func test_removeDirectory_excludingIntermediateDirectories_directoryDoesntHaveContent_shouldBeSuccessful() throws { // Given - let fileManager = createFileManager() + let fileManager = createFileManager(exclusions: []) let testDirectory = URL(filePath: "/test/directory") let shouldIncludeIntermediateDirectories = false @@ -109,7 +123,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase { } func test_removeDirectory_excludingIntermediateDirectories_directoryHasContent_shouldReturnAnError() { - createFileManager(shouldDirectoryHaveContent: true) + createFileManager(shouldDirectoryHaveContent: true, exclusions: []) let testDirectory = URL(filePath: "/test/directory") let shouldIncludeIntermediateDirectories = false @@ -125,7 +139,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase { // MARK: - 'listDirectory' tests func test_listDirectory_withNoContent_shouldReturnEmptyArray() throws { // Given - let fileManager = createFileManager() + let fileManager = createFileManager(exclusions: []) let testDirectory = URL(filePath: "/test/directory") // When @@ -139,7 +153,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase { // MARK: - 'listDirectory' tests func test_listDirectory_withContent_shouldReturnNotEmptyArray() throws { // Given - let fileManager = createFileManager(shouldDirectoryHaveContent: true) + let fileManager = createFileManager(shouldDirectoryHaveContent: true, exclusions: []) let testDirectory = URL(filePath: "/test/directory") // When @@ -153,7 +167,7 @@ final class IONFILEDirectoryManagerTests: XCTestCase { func test_listDirectory_butFails_shouldReturnAnError() { // Given let error = MockFileManagerError.readDirectoryError - createFileManager(with: error) + createFileManager(with: error, exclusions: []) let testDirectory = URL(filePath: "/test/directory") // When @@ -164,6 +178,20 @@ final class IONFILEDirectoryManagerTests: XCTestCase { XCTAssertEqual($0 as? MockFileManagerError, error) } } + + func test_listDirectory_butFails_shouldReturnFileNotFound() { + // Given + createFileManager(fileExists: false, exclusions: []) + let testDirectory = URL(filePath: "/test/directory") + + // When + XCTAssertThrowsError( + try sut.listDirectory(atURL: testDirectory) + ) { + // Then + XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: testDirectory.urlPath)) + } + } } private extension IONFILEDirectoryManagerTests { diff --git a/IONFilesystemLibTests/IONFILEFileManagerTests.swift b/IONFilesystemLibTests/IONFILEFileManagerTests.swift index 654e48c..0b069a1 100644 --- a/IONFilesystemLibTests/IONFILEFileManagerTests.swift +++ b/IONFilesystemLibTests/IONFILEFileManagerTests.swift @@ -54,6 +54,18 @@ extension IONFILEFileManagerTests { XCTAssertThrowsError(try fetchEntireContent(forURL: fileURL, withEncoding: .string(encoding: .utf8))) } + func test_readEntireFile_thatDoesntExist_returnsFileNotFound() throws { + // Given + createFileManager(fileExists: false) + let fileURL = URL(filePath: "/file/directory") + + // When + XCTAssertThrowsError(try sut.readEntireFile(atURL: fileURL, withEncoding: .string(encoding: .utf8))) { + //Then + XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: fileURL.urlPath)) + } + } + func test_readEntireFile_offsetAndLengthWithExampleEncoding_returnsCorrectData() throws { // Given createFileManager() @@ -104,7 +116,7 @@ extension IONFILEFileManagerTests { let result = try sut.readEntireFile(atURL: fileURL, withEncoding: .string(encoding: encoding), andOffset: offset, andLength: length) // Then - guard case .string(let resultEncoding, let resultValue) = result else { + guard case .string(_, let resultValue) = result else { XCTFail("Wrong result type") return } @@ -162,6 +174,18 @@ extension IONFILEFileManagerTests { XCTAssertThrowsError(try fetchChunkedContent(forURL: fileURL, withEncoding: .string(encoding: .utf8))) } + func test_readFileInChunks_thatDoesntExist_returnsFileNotFound() throws { + // Given + createFileManager(fileExists: false) + let fileURL = URL(filePath: "/file/directory") + + // When + XCTAssertThrowsError(try fetchChunkedContent(forURL: fileURL, withEncoding: .string(encoding: .utf8))) { + // Then + XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: fileURL.urlPath)) + } + } + func test_readFileInChunks_withOffsetAndLength_returnsContentSuccessfully() throws { // Given createFileManager() @@ -505,11 +529,11 @@ extension IONFILEFileManagerTests { // Then XCTAssertEqual(fileManager.capturedIntermediateDirectories, shouldIncludeIntermediateDirectories) XCTAssertEqual(fileManager.capturedPath, parentFolderURL) - + + fileManager.fileExists = true let savedFileContent = try fetchEntireContent(forURL: fileURL, withEncoding: .string(encoding: stringEncoding)) XCTAssertEqual(savedFileContent, contentToSave) - - fileManager.fileExists = true + try sut.deleteFile(atURL: fileURL) // keep things clean by deleting created file } @@ -610,11 +634,11 @@ extension IONFILEFileManagerTests { XCTAssertEqual(fileManager.capturedIntermediateDirectories, shouldIncludeIntermediateDirectories) // Then + fileManager.fileExists = true let savedFileContent = try fetchEntireContent(forURL: fileURL, withEncoding: .string(encoding: stringEncoding)) XCTAssertEqual(savedFileContent, contentToAdd) - fileManager.fileExists = true try sut.deleteFile(atURL: fileURL) // keep things clean by deleting created file } @@ -731,13 +755,25 @@ extension IONFILEFileManagerTests { XCTAssertEqual($0 as? MockFileManagerError, error) } } + + func test_getItemAttributes_fileDoesntExist_returnsFileNotFound() { + // Given + createFileManager(fileExists: false) + let testURL = URL(filePath: "/test/missing-file") + + // When + XCTAssertThrowsError(try sut.getItemAttributes(atURL: testURL)) { + // Then + XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: testURL.urlPath)) + } + } } // MARK: - 'renameItem' tests extension IONFILEFileManagerTests { func test_renameItem_shouldBeSuccessful() throws { // Given - let fileManager = createFileManager(fileExists: false) + let fileManager = createFileManager() let originPath = URL(filePath: "/test/origin") let destinationPath = URL(filePath: "/test/destination") @@ -751,7 +787,7 @@ extension IONFILEFileManagerTests { func test_renameItem_sameOriginAndDestination_shouldDoNothing() throws { // Given - let fileManager = createFileManager(fileExists: false) + let fileManager = createFileManager() let originPath = URL(filePath: "/test/origin") let destinationPath = URL(filePath: "/test/origin") @@ -762,6 +798,19 @@ extension IONFILEFileManagerTests { XCTAssertNil(fileManager.capturedOriginPath) XCTAssertNil(fileManager.capturedDestinationPath) } + + func test_renameItem_fileDoesntExist_returnsFileNotFound() { + // Given + createFileManager(fileExists: false) + let originPath = URL(filePath: "/test/origin") + let destinationPath = URL(filePath: "/test/destination") + + // When + XCTAssertThrowsError(try sut.renameItem(fromURL: originPath, toURL: destinationPath)) { + // Then + XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: originPath.urlPath)) + } + } func test_renameDirectory_alreadyExisting_shouldBeSuccessful() throws { // Given @@ -811,7 +860,7 @@ extension IONFILEFileManagerTests { extension IONFILEFileManagerTests { func test_copyItem_shouldBeSuccessful() throws { // Given - let fileManager = createFileManager(fileExists: false) + let fileManager = createFileManager() let originPath = URL(filePath: "/test/origin") let destinationPath = URL(filePath: "/test/destination") @@ -825,7 +874,7 @@ extension IONFILEFileManagerTests { func test_copyItem_sameOriginAndDestination_shouldDoNothing() throws { // Given - let fileManager = createFileManager(fileExists: false) + let fileManager = createFileManager() let originPath = URL(filePath: "/test/origin") let destinationPath = URL(filePath: "/test/origin") @@ -837,6 +886,19 @@ extension IONFILEFileManagerTests { XCTAssertNil(fileManager.capturedDestinationPath) } + + func test_copyItem_fileDoesntExist_returnsFileNotFound() { + // Given + createFileManager(fileExists: false) + let originPath = URL(filePath: "/test/origin") + let destinationPath = URL(filePath: "/test/destination") + + // When + XCTAssertThrowsError(try sut.copyItem(fromURL: originPath, toURL: destinationPath)) { + // Then + XCTAssertEqual($0 as? IONFILEFileManagerError, .fileNotFound(atPath: originPath.urlPath)) + } + } func test_copyDirectory_alreadyExisting_shouldBeSuccessful() throws { // Given