diff --git a/Library/Sources/Extensions/URL+Extensions.swift b/Library/Sources/Extensions/URL+Extensions.swift index 04b5999..01d4ea3 100644 --- a/Library/Sources/Extensions/URL+Extensions.swift +++ b/Library/Sources/Extensions/URL+Extensions.swift @@ -16,7 +16,7 @@ extension URL { var pathString: String { if #available(macOS 13.0, *) { - path() + path(percentEncoded: true) } else { path } diff --git a/Library/Sources/Services/FileService.swift b/Library/Sources/Services/FileService.swift index 9269340..d7e1fdb 100644 --- a/Library/Sources/Services/FileService.swift +++ b/Library/Sources/Services/FileService.swift @@ -23,9 +23,6 @@ public struct FileService: FileServicing { // MARK: Functions public func copyFile(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 } diff --git a/Library/Sources/Tasks/CopyFilesTask.swift b/Library/Sources/Tasks/CopyFilesTask.swift index 182f19a..f91212e 100644 --- a/Library/Sources/Tasks/CopyFilesTask.swift +++ b/Library/Sources/Tasks/CopyFilesTask.swift @@ -4,50 +4,36 @@ public struct CopyFilesTask { // MARK: Properties + private let bundleService: BundleServicing private let fileService: FileServicing // MARK: Initialisers - public init(fileService: FileServicing) { + public init( + bundleService: BundleServicing? = nil, + fileService: FileServicing + ) { + self.bundleService = bundleService ?? Bundle.module self.fileService = fileService } // MARK: Functions - public func callAsFunction(to rootFolder: URL) async throws { - let filesFolder = URL(at: .folderFiles) - - for fileToCopy in Self.filesToCopy { - try await fileService.copyItem( - from: filesFolder.appendingPath(fileToCopy), - to: rootFolder.appendingPath(fileToCopy) - ) + public func callAsFunction(to rootFolder: URL) async throws (FileServiceError) { + for resource in ResourceFile.allCases { + guard let source = bundleService.url( + forResource: resource.rawValue, + withExtension: nil, + subdirectory: "Resources/Files" + ) else { + assertionFailure("URL should have been initialized.") + return + } + + let destination = rootFolder.appendingPath(resource.fileName) + + try await fileService.copyFile(from: source, to: destination) } } } - -// MARK: - Helpers - -extension CopyFilesTask { - - // MARK: Constants - - static let filesToCopy: [String] = [ - .fileDockerIgnore, - .fileGitIgnore, - .fileLicense, - .fileReadme - ] - -} - -// MARK: - URL+Constants - -private extension String { - static let folderFiles = "./Resources/Files" - static let fileDockerIgnore = ".dockerignore" - static let fileGitIgnore = ".gitignore" - static let fileLicense = "LICENSE" - static let fileReadme = "README.md" -} diff --git a/Library/Sources/Tasks/CreateFoldersTask.swift b/Library/Sources/Tasks/CreateFoldersTask.swift index a0a3531..2db9de9 100644 --- a/Library/Sources/Tasks/CreateFoldersTask.swift +++ b/Library/Sources/Tasks/CreateFoldersTask.swift @@ -31,19 +31,10 @@ extension CreateFoldersTask { // MARK: Constants static let foldersToCreate: [String] = [ - .folderApp, - .folderAppInfrastructure, - .folderAppTestCases, - .folderAppTestSources + "Sources/App", + "Sources/AppInfrastructure", + "Tests/App/Cases", + "Tests/App/Sources" ] } - -// MARK: - String+Constants - -private extension String { - static let folderApp = "Sources/App" - static let folderAppInfrastructure = "Sources/AppInfrastructure" - static let folderAppTestCases = "Tests/App/Cases" - static let folderAppTestSources = "Tests/App/Sources" -} diff --git a/Test/Sources/Cases/Services/FileServiceTests.swift b/Test/Sources/Cases/Services/FileServiceTests.swift index e66dd0b..7cc9e5f 100644 --- a/Test/Sources/Cases/Services/FileServiceTests.swift +++ b/Test/Sources/Cases/Services/FileServiceTests.swift @@ -47,7 +47,7 @@ struct FileServiceTests { #expect(action == .fileCopied(source, destination)) } - @Test(arguments: [FileServiceError.itemNotExists, .itemAlreadyExists, .itemEmptyData, .itemNotCopied]) + @Test(arguments: [FileServiceError.itemAlreadyExists, .itemEmptyData, .itemNotCopied]) func copyItem(throws error: FileServiceError) async throws { // GIVEN let service = FileServiceMock( diff --git a/Test/Sources/Cases/Tasks/CopyFilesTaskTests.swift b/Test/Sources/Cases/Tasks/CopyFilesTaskTests.swift index b473717..fc1a18e 100644 --- a/Test/Sources/Cases/Tasks/CopyFilesTaskTests.swift +++ b/Test/Sources/Cases/Tasks/CopyFilesTaskTests.swift @@ -7,37 +7,74 @@ struct CopyFilesTaskTests { // MARK: Properties + private let resourceFolder = URL.someExistingFolder + private let rootFolder = URL.someNewFolder + private let spy = FileServiceSpy() // MARK: Functions tests - @Test(arguments: zip([URL.someExistingFolder], [URL.someNewFolder])) - func copyFiles(from source: URL, to destination: URL) async throws { + @Test func copyFiles() async throws { // GIVEN - let filesToCopy = CopyFilesTask.filesToCopy - let destinations = filesToCopy.map { destination.appendingPath($0) } - let sources = filesToCopy.map { source.appendingPath($0) } - let actions = filesToCopy.indices.map { index -> FileServiceMock.Action in - .copyItem(sources[index], destinations[index]) - } + let files = files(of: ResourceFile.allCases) + let actions = files.map { FileServiceMock.Action.copyFile($0.source, $0.destination) } - let service = FileServiceMock( + let copyFiles = CopyFilesTask(fileService: FileServiceMock( currentFolder: .someCurrentFolder, actions: actions, spy: spy - ) - - let copyFiles = CopyFilesTask(fileService: service) + )) // WHEN - try await copyFiles(to: destination) + try await copyFiles(to: rootFolder) // THEN #expect(spy.actions.count == actions.count) - for index in actions.indices { - #expect(spy.actions[index] == .itemCopied(sources[index], destinations[index])) + files.enumerated().forEach { index, file in + #expect(spy.actions[index] == .fileCopied(file.source, file.destination)) + } + } + + @Test(arguments: [FileServiceError.itemAlreadyExists, .itemEmptyData, .itemNotCopied]) + func copyFiles(throws error: FileServiceError) async throws { + // GIVEN + let files = files(of: Array(ResourceFile.allCases[0...2])) + let actions = files.map { FileServiceMock.Action.copyFile($0.source, $0.destination) } + + let copyFiles = CopyFilesTask(fileService: FileServiceMock( + currentFolder: .someCurrentFolder, + actions: actions + [.error(error)], + spy: spy + )) + + // WHEN + // THEN + await #expect(throws: error) { + try await copyFiles(to: rootFolder) + } + + #expect(spy.actions.count == actions.count) + + files.enumerated().forEach { index, file in + #expect(spy.actions[index] == .fileCopied(file.source, file.destination)) } } } + +// MARK: - Helpers + +private extension CopyFilesTaskTests { + + // MARK: Type aliases + + typealias File = (source: URL, destination: URL) + + // MARK: Functions + + func files(of resourceFiles: [ResourceFile]) -> [File] { + resourceFiles.map { (resourceFolder.appendingPath($0.rawValue), rootFolder.appendingPath($0.fileName)) } + } + +}