Root folder creation (#2)

This PR contains the work done to create the root folder of a new project when executing the _colibri_ executable. In addition, some other work has been done:

* added the `ArgumentParser` package dependency to the package;
* implemented the `FileService` service in the _library_ target;
* implemented the `CreateRootFolderTask` task in the _library_ target;
* removed some unnecessary comments and boilerplate code;

Reviewed-on: #2
Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This commit was merged in pull request #2.
This commit is contained in:
2025-01-27 23:54:50 +00:00
committed by Javier Cicchelli
parent d0d47d280d
commit b8c354e614
12 changed files with 619 additions and 5 deletions
@@ -0,0 +1,18 @@
import Foundation
@testable import ColibriLibrary
extension URL {
// MARK: Constants
static let someCurrentFolder = URL(at: "/some/current/folder")
static let someDotFolder = URL(at: ".")
static let someExistingFolder = URL(at: "/some/existing/folder")
static let someExistingFile = URL(at: "/some/existing/file")
static let someNewFolder = URL(at: "/some/new/folder")
static let someNewFile = URL(at: "/some/new/file")
static let someRandomURL = URL(string: "http://some.random.url")!
static let someTildeFolder = URL(at: "~")
}
@@ -0,0 +1,84 @@
import ColibriLibrary
import Foundation
struct FileServiceMock {
// MARK: Properties
private let action: Action?
private let folder: URL
private weak var spy: FileServiceSpy?
// MARK: Initialisers
init(
currentFolder: URL,
action: Action? = nil,
spy: FileServiceSpy? = nil
) {
self.action = action
self.folder = currentFolder
self.spy = spy
}
}
// MARK: - FileServicing
extension FileServiceMock: FileServicing {
// MARK: Computed
var currentFolder: URL {
get async { folder }
}
// MARK: Functions
func createFolder(at url: URL) async throws(FileServiceError) {
switch action {
case .error(let error):
throw error
case let .createFolder(url):
try await spy?.createFolder(at: url)
default:
break
}
}
func delete(at url: URL) async throws(FileServiceError) {
switch action {
case .error(let error):
throw error
case let .delete(url):
try await spy?.delete(at: url)
default:
break
}
}
func exists(at url: URL) async throws(FileServiceError) -> Bool {
switch action {
case .error(let error):
throw error
case let .exists(url, exists):
try await spy?.exists(at: url)
return exists
default:
return false
}
}
}
// MARK: - Enumerations
extension FileServiceMock {
enum Action {
case createFolder(URL)
case delete(URL)
case error(FileServiceError)
case exists(URL, Bool)
}
}
@@ -0,0 +1,41 @@
import Foundation
@testable import ColibriLibrary
final class FileServiceSpy {
// MARK: Properties
private(set) var isCreateFolderCalled: Bool = false
private(set) var isDeleteCalled: Bool = false
private(set) var isExistsAtCalled: Bool = false
private(set) var urlCalled: URL?
}
// MARK: - FileServicing
extension FileServiceSpy: FileServicing {
var currentFolder: URL {
get async { .someCurrentFolder }
}
func createFolder(at url: URL) async throws(FileServiceError) {
isCreateFolderCalled = true
urlCalled = url
}
func delete(at url: URL) async throws(FileServiceError) {
isDeleteCalled = true
urlCalled = url
}
@discardableResult
func exists(at url: URL) async throws(FileServiceError) -> Bool {
isExistsAtCalled = true
urlCalled = url
return .random()
}
}