From b8d5bea7ae42ba21c3bc7f7bef08a058188f88fc Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sat, 18 Jan 2025 01:07:52 +0100 Subject: [PATCH] Implemented the "copyFile(from: to: )" function for the FileService service in the library target. --- Library/Sources/Protocols/FileServicing.swift | 5 +++-- Library/Sources/Services/FileService.swift | 12 ++++++++++-- Test/Sources/Cases/Services/FileServiceTests.swift | 12 ++++++------ Test/Sources/Helpers/Mocks/FileServiceMock.swift | 8 ++++---- Test/Sources/Helpers/Spies/FileServiceSpy.swift | 6 +++--- 5 files changed, 26 insertions(+), 17 deletions(-) diff --git a/Library/Sources/Protocols/FileServicing.swift b/Library/Sources/Protocols/FileServicing.swift index 674499e..4de66e3 100644 --- a/Library/Sources/Protocols/FileServicing.swift +++ b/Library/Sources/Protocols/FileServicing.swift @@ -8,7 +8,7 @@ public protocol FileServicing { // MARK: Functions - func copyItem(from source: URL, to destination: URL) async throws (FileServiceError) + func copyFile(from source: URL, to destination: URL) async throws (FileServiceError) func createFolder(at location: URL) async throws (FileServiceError) func deleteItem(at location: URL) async throws (FileServiceError) func isItemExists(at location: URL) async throws (FileServiceError) -> Bool @@ -19,8 +19,9 @@ public protocol FileServicing { public enum FileServiceError: Error, Equatable { case folderNotCreated - case itemNotCopied case itemAlreadyExists + case itemEmptyData + case itemNotCopied case itemNotDeleted case itemNotExists case itemNotFileURL diff --git a/Library/Sources/Services/FileService.swift b/Library/Sources/Services/FileService.swift index 3df4be9..9269340 100644 --- a/Library/Sources/Services/FileService.swift +++ b/Library/Sources/Services/FileService.swift @@ -22,7 +22,7 @@ public struct FileService: FileServicing { // MARK: Functions - public func copyItem(from source: URL, to destination: URL) async throws (FileServiceError) { + public func copyFile(from source: URL, to destination: URL) async throws (FileServiceError) { guard try await isItemExists(at: source) else { throw FileServiceError.itemNotExists } @@ -30,8 +30,16 @@ public struct FileService: FileServicing { throw FileServiceError.itemAlreadyExists } + var itemData: Data? + do { - try fileManager.copyItem(at: source, to: destination) + itemData = try Data(contentsOf: source) + } catch { + throw FileServiceError.itemEmptyData + } + + do { + try itemData?.write(to: destination, options: .atomic) } catch { throw FileServiceError.itemNotCopied } diff --git a/Test/Sources/Cases/Services/FileServiceTests.swift b/Test/Sources/Cases/Services/FileServiceTests.swift index 2edbc48..e66dd0b 100644 --- a/Test/Sources/Cases/Services/FileServiceTests.swift +++ b/Test/Sources/Cases/Services/FileServiceTests.swift @@ -28,26 +28,26 @@ struct FileServiceTests { @Test(arguments: zip([URL.someExistingFile, .someExistingFolder], [URL.someNewFile, .someNewFolder])) - func copyItem(from source: URL, to destination: URL) async throws { + func copyFile(from source: URL, to destination: URL) async throws { // GIVEN let service = FileServiceMock( currentFolder: .someCurrentFolder, - action: .copyItem(source, destination), + action: .copyFile(source, destination), spy: spy ) // WHEN - try await service.copyItem(from: source, to: destination) + try await service.copyFile(from: source, to: destination) // THENn #expect(spy.actions.count == 1) let action = try #require(spy.actions.last) - #expect(action == .itemCopied(source, destination)) + #expect(action == .fileCopied(source, destination)) } - @Test(arguments: [FileServiceError.itemNotExists, .itemAlreadyExists, .itemNotCopied]) + @Test(arguments: [FileServiceError.itemNotExists, .itemAlreadyExists, .itemEmptyData, .itemNotCopied]) func copyItem(throws error: FileServiceError) async throws { // GIVEN let service = FileServiceMock( @@ -59,7 +59,7 @@ struct FileServiceTests { // WHEN // THEN await #expect(throws: error) { - try await service.copyItem(from: .someExistingFile, to: .someNewFile) + try await service.copyFile(from: .someExistingFile, to: .someNewFile) } #expect(spy.actions.isEmpty == true) diff --git a/Test/Sources/Helpers/Mocks/FileServiceMock.swift b/Test/Sources/Helpers/Mocks/FileServiceMock.swift index 8d11b64..99bd117 100644 --- a/Test/Sources/Helpers/Mocks/FileServiceMock.swift +++ b/Test/Sources/Helpers/Mocks/FileServiceMock.swift @@ -51,14 +51,14 @@ extension FileServiceMock: FileServicing { // MARK: Functions - func copyItem(from source: URL, to destination: URL) async throws (FileServiceError) { + func copyFile(from source: URL, to destination: URL) async throws (FileServiceError) { guard let nextAction else { return } switch nextAction { case .error(let error): throw error - case let .copyItem(source, destination): - try await spy?.copyItem(from: source, to: destination) + case let .copyFile(source, destination): + try await spy?.copyFile(from: source, to: destination) default: break } @@ -126,7 +126,7 @@ private extension FileServiceMock { extension FileServiceMock { enum Action { - case copyItem(URL, URL) + case copyFile(URL, URL) case createFolder(URL) case deleteItem(URL) case error(FileServiceError) diff --git a/Test/Sources/Helpers/Spies/FileServiceSpy.swift b/Test/Sources/Helpers/Spies/FileServiceSpy.swift index 3b21653..34ccd63 100644 --- a/Test/Sources/Helpers/Spies/FileServiceSpy.swift +++ b/Test/Sources/Helpers/Spies/FileServiceSpy.swift @@ -18,8 +18,8 @@ extension FileServiceSpy: FileServicing { get async { .someCurrentFolder } } - func copyItem(from source: URL, to destination: URL) async throws (FileServiceError) { - actions.append(.itemCopied(source, destination)) + func copyFile(from source: URL, to destination: URL) async throws (FileServiceError) { + actions.append(.fileCopied(source, destination)) } func createFolder(at location: URL) async throws (FileServiceError) { @@ -43,8 +43,8 @@ extension FileServiceSpy: FileServicing { extension FileServiceSpy { enum Action: Equatable { + case fileCopied(_ source: URL, _ destination: URL) case folderCreated(_ location: URL) - case itemCopied(_ source: URL, _ destination: URL) case itemDeleted(_ location: URL) case itemExists(_ location: URL) }