From 489cf3d780c947e2d97f24c634ca65549f4ae708 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Tue, 14 Jan 2025 23:52:33 +0100 Subject: [PATCH] Implemented the "copyItem(from: to: )" function for the FileService service in the library target. --- Sources/Library/Protocols/FileServicing.swift | 2 + Sources/Library/Services/FileService.swift | 15 +++++++ .../Cases/Services/FileServiceTests.swift | 39 +++++++++++++++++++ .../Helpers/Mocks/FileServiceMock.swift | 14 +++++++ .../Helpers/Spies/FileServiceSpy.swift | 3 ++ 5 files changed, 73 insertions(+) diff --git a/Sources/Library/Protocols/FileServicing.swift b/Sources/Library/Protocols/FileServicing.swift index 011c47a..674499e 100644 --- a/Sources/Library/Protocols/FileServicing.swift +++ b/Sources/Library/Protocols/FileServicing.swift @@ -8,6 +8,7 @@ public protocol FileServicing { // MARK: Functions + func copyItem(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 @@ -18,6 +19,7 @@ public protocol FileServicing { public enum FileServiceError: Error, Equatable { case folderNotCreated + case itemNotCopied case itemAlreadyExists case itemNotDeleted case itemNotExists diff --git a/Sources/Library/Services/FileService.swift b/Sources/Library/Services/FileService.swift index acc4e7c..3df4be9 100644 --- a/Sources/Library/Services/FileService.swift +++ b/Sources/Library/Services/FileService.swift @@ -21,6 +21,21 @@ public struct FileService: FileServicing { } // MARK: Functions + + public func copyItem(from source: URL, to destination: URL) async throws (FileServiceError) { + guard try await isItemExists(at: source) else { + throw FileServiceError.itemNotExists + } + guard try await !isItemExists(at: destination) else { + throw FileServiceError.itemAlreadyExists + } + + do { + try fileManager.copyItem(at: source, to: destination) + } catch { + throw FileServiceError.itemNotCopied + } + } public func createFolder(at location: URL) async throws (FileServiceError) { guard try await !isItemExists(at: location) else { diff --git a/Tests/Library/Cases/Services/FileServiceTests.swift b/Tests/Library/Cases/Services/FileServiceTests.swift index 5df3b97..2edbc48 100644 --- a/Tests/Library/Cases/Services/FileServiceTests.swift +++ b/Tests/Library/Cases/Services/FileServiceTests.swift @@ -26,6 +26,45 @@ struct FileServiceTests { // MARK: Functions tests + @Test(arguments: zip([URL.someExistingFile, .someExistingFolder], + [URL.someNewFile, .someNewFolder])) + func copyItem(from source: URL, to destination: URL) async throws { + // GIVEN + let service = FileServiceMock( + currentFolder: .someCurrentFolder, + action: .copyItem(source, destination), + spy: spy + ) + + // WHEN + try await service.copyItem(from: source, to: destination) + + // THENn + #expect(spy.actions.count == 1) + + let action = try #require(spy.actions.last) + + #expect(action == .itemCopied(source, destination)) + } + + @Test(arguments: [FileServiceError.itemNotExists, .itemAlreadyExists, .itemNotCopied]) + func copyItem(throws error: FileServiceError) async throws { + // GIVEN + let service = FileServiceMock( + currentFolder: .someCurrentFolder, + action: .error(error), + spy: spy + ) + + // WHEN + // THEN + await #expect(throws: error) { + try await service.copyItem(from: .someExistingFile, to: .someNewFile) + } + + #expect(spy.actions.isEmpty == true) + } + @Test(arguments: [URL.someNewFolder, .someNewFile]) func createFolder(with location: URL) async throws { // GIVEN diff --git a/Tests/Library/Helpers/Mocks/FileServiceMock.swift b/Tests/Library/Helpers/Mocks/FileServiceMock.swift index dbc7368..8d11b64 100644 --- a/Tests/Library/Helpers/Mocks/FileServiceMock.swift +++ b/Tests/Library/Helpers/Mocks/FileServiceMock.swift @@ -51,6 +51,19 @@ extension FileServiceMock: FileServicing { // MARK: Functions + func copyItem(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) + default: + break + } + } + func createFolder(at location: URL) async throws (FileServiceError) { guard let nextAction else { return } @@ -113,6 +126,7 @@ private extension FileServiceMock { extension FileServiceMock { enum Action { + case copyItem(URL, URL) case createFolder(URL) case deleteItem(URL) case error(FileServiceError) diff --git a/Tests/Library/Helpers/Spies/FileServiceSpy.swift b/Tests/Library/Helpers/Spies/FileServiceSpy.swift index 3906733..3b21653 100644 --- a/Tests/Library/Helpers/Spies/FileServiceSpy.swift +++ b/Tests/Library/Helpers/Spies/FileServiceSpy.swift @@ -18,6 +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 createFolder(at location: URL) async throws (FileServiceError) { @@ -42,6 +44,7 @@ extension FileServiceSpy: FileServicing { extension FileServiceSpy { enum Action: Equatable { case folderCreated(_ location: URL) + case itemCopied(_ source: URL, _ destination: URL) case itemDeleted(_ location: URL) case itemExists(_ location: URL) }