Basic project creation (#3)

This PR contains the work done to create a new *Hummingbird* project with very basic configuration from the _colibri_ executable, just like the project you could create with the [Hummingbird template](https://github.com/hummingbird-project/template) project in Github.

Reviewed-on: #3
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 #3.
This commit is contained in:
2025-01-28 00:07:24 +00:00
committed by Javier Cicchelli
parent b8c354e614
commit 9be8fa4a31
52 changed files with 1936 additions and 475 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,135 @@
import ColibriLibrary
import Foundation
final class FileServiceMock {
// MARK: Properties
private let folder: URL
private var actions: [Action] = []
private weak var spy: FileServiceSpy?
// MARK: Initialisers
init(
currentFolder: URL,
action: Action? = nil,
spy: FileServiceSpy? = nil
) {
self.actions = if let action {
[action]
} else {
[]
}
self.folder = currentFolder
self.spy = spy
}
init(
currentFolder: URL,
actions: [Action],
spy: FileServiceSpy? = nil
) {
self.actions = actions
self.folder = currentFolder
self.spy = spy
}
}
// MARK: - FileServicing
extension FileServiceMock: FileServicing {
// MARK: Computed
var currentFolder: URL {
get async { folder }
}
// MARK: Functions
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 .copyFile(source, destination):
try await spy?.copyFile(from: source, to: destination)
default:
break
}
}
func createFolder(at location: URL) async throws (FileServiceError) {
guard let nextAction else { return }
switch nextAction {
case .error(let error):
throw error
case let .createFolder(location):
try await spy?.createFolder(at: location)
default:
break
}
}
func deleteItem(at location: URL) async throws (FileServiceError) {
guard let nextAction else { return }
switch nextAction {
case .error(let error):
throw error
case let .deleteItem(location):
try await spy?.deleteItem(at: location)
default:
break
}
}
func isItemExists(at location: URL) async throws (FileServiceError) -> Bool {
guard let nextAction else { return false }
switch nextAction {
case .error(let error):
throw error
case let .isItemExists(location, exists):
try await spy?.isItemExists(at: location)
return exists
default:
return false
}
}
}
// MARK: - Helpers
private extension FileServiceMock {
// MARK: Computed
var nextAction: Action? {
guard !actions.isEmpty else {
return nil
}
return actions.removeFirst()
}
}
// MARK: - Actions
extension FileServiceMock {
enum Action {
case copyFile(URL, URL)
case createFolder(URL)
case deleteItem(URL)
case error(FileServiceError)
case isItemExists(URL, Bool)
}
}
@@ -0,0 +1,51 @@
import Foundation
@testable import ColibriLibrary
final class FileServiceSpy {
// MARK: Properties
private(set) var actions: [Action] = []
}
// MARK: - FileServicing
extension FileServiceSpy: FileServicing {
var currentFolder: URL {
get async { .someCurrentFolder }
}
func copyFile(from source: URL, to destination: URL) async throws (FileServiceError) {
actions.append(.fileCopied(source, destination))
}
func createFolder(at location: URL) async throws (FileServiceError) {
actions.append(.folderCreated(location))
}
func deleteItem(at location: URL) async throws (FileServiceError) {
actions.append(.itemDeleted(location))
}
@discardableResult
func isItemExists(at location: URL) async throws (FileServiceError) -> Bool {
actions.append(.itemExists(location))
return .random()
}
}
// MARK: - Action
extension FileServiceSpy {
enum Action: Equatable {
case fileCopied(_ source: URL, _ destination: URL)
case folderCreated(_ location: URL)
case itemDeleted(_ location: URL)
case itemExists(_ location: URL)
}
}