Implemented the "createFile(at: with: )" function for the FileService service in the library target.
This commit is contained in:
parent
3dcb110de1
commit
33ae67fc58
@ -9,6 +9,7 @@ public protocol FileServicing {
|
|||||||
// MARK: Functions
|
// MARK: Functions
|
||||||
|
|
||||||
func copyFile(from source: URL, to destination: URL) async throws (FileServiceError)
|
func copyFile(from source: URL, to destination: URL) async throws (FileServiceError)
|
||||||
|
func createFile(at location: URL, with data: Data) async throws (FileServiceError)
|
||||||
func createFolder(at location: URL) async throws (FileServiceError)
|
func createFolder(at location: URL) async throws (FileServiceError)
|
||||||
func deleteItem(at location: URL) async throws (FileServiceError)
|
func deleteItem(at location: URL) async throws (FileServiceError)
|
||||||
func isItemExists(at location: URL) async throws (FileServiceError) -> Bool
|
func isItemExists(at location: URL) async throws (FileServiceError) -> Bool
|
||||||
@ -18,6 +19,8 @@ public protocol FileServicing {
|
|||||||
// MARK: - Errors
|
// MARK: - Errors
|
||||||
|
|
||||||
public enum FileServiceError: Error, Equatable {
|
public enum FileServiceError: Error, Equatable {
|
||||||
|
case fileDataIsEmpty
|
||||||
|
case fileNotCreated
|
||||||
case folderNotCreated
|
case folderNotCreated
|
||||||
case itemAlreadyExists
|
case itemAlreadyExists
|
||||||
case itemEmptyData
|
case itemEmptyData
|
||||||
|
@ -30,7 +30,7 @@ extension FileService: FileServicing {
|
|||||||
|
|
||||||
public func copyFile(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: destination) else {
|
guard try await !isItemExists(at: destination) else {
|
||||||
throw FileServiceError.itemAlreadyExists
|
throw .itemAlreadyExists
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemData: Data?
|
var itemData: Data?
|
||||||
@ -38,43 +38,59 @@ extension FileService: FileServicing {
|
|||||||
do {
|
do {
|
||||||
itemData = try Data(contentsOf: source)
|
itemData = try Data(contentsOf: source)
|
||||||
} catch {
|
} catch {
|
||||||
throw FileServiceError.itemEmptyData
|
throw .itemEmptyData
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try itemData?.write(to: destination, options: .atomic)
|
try itemData?.write(to: destination, options: .atomic)
|
||||||
} catch {
|
} catch {
|
||||||
throw FileServiceError.itemNotCopied
|
throw .itemNotCopied
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func createFile(at location: URL, with data: Data) async throws (FileServiceError) {
|
||||||
|
guard try await !isItemExists(at: location) else {
|
||||||
|
throw .itemAlreadyExists
|
||||||
|
}
|
||||||
|
|
||||||
|
guard !data.isEmpty else {
|
||||||
|
throw .fileDataIsEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
try data.write(to: location, options: .atomic)
|
||||||
|
} catch {
|
||||||
|
throw .fileNotCreated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func createFolder(at location: URL) async throws (FileServiceError) {
|
public func createFolder(at location: URL) async throws (FileServiceError) {
|
||||||
guard try await !isItemExists(at: location) else {
|
guard try await !isItemExists(at: location) else {
|
||||||
throw FileServiceError.itemAlreadyExists
|
throw .itemAlreadyExists
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try fileManager.createDirectory(at: location, withIntermediateDirectories: true)
|
try fileManager.createDirectory(at: location, withIntermediateDirectories: true)
|
||||||
} catch {
|
} catch {
|
||||||
throw FileServiceError.folderNotCreated
|
throw .folderNotCreated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deleteItem(at location: URL) async throws (FileServiceError) {
|
public func deleteItem(at location: URL) async throws (FileServiceError) {
|
||||||
guard try await isItemExists(at: location) else {
|
guard try await isItemExists(at: location) else {
|
||||||
throw FileServiceError.itemNotExists
|
throw .itemNotExists
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try fileManager.removeItem(at: location)
|
try fileManager.removeItem(at: location)
|
||||||
} catch {
|
} catch {
|
||||||
throw FileServiceError.itemNotDeleted
|
throw .itemNotDeleted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func isItemExists(at location: URL) async throws (FileServiceError) -> Bool {
|
public func isItemExists(at location: URL) async throws (FileServiceError) -> Bool {
|
||||||
guard location.isFileURL else {
|
guard location.isFileURL else {
|
||||||
throw FileServiceError.itemNotFileURL
|
throw .itemNotFileURL
|
||||||
}
|
}
|
||||||
|
|
||||||
let filePath = location.pathString
|
let filePath = location.pathString
|
||||||
|
@ -35,7 +35,7 @@ struct FileServiceTests {
|
|||||||
// WHEN
|
// WHEN
|
||||||
try await service.copyFile(from: source, to: destination)
|
try await service.copyFile(from: source, to: destination)
|
||||||
|
|
||||||
// THENn
|
// THEN
|
||||||
#expect(spy.actions.count == 1)
|
#expect(spy.actions.count == 1)
|
||||||
|
|
||||||
let action = try #require(spy.actions.last)
|
let action = try #require(spy.actions.last)
|
||||||
@ -57,6 +57,37 @@ struct FileServiceTests {
|
|||||||
#expect(spy.actions.isEmpty == true)
|
#expect(spy.actions.isEmpty == true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(arguments: zip([URL.someNewFile],
|
||||||
|
[Data("some data goes here...".utf8)]))
|
||||||
|
func createFile(with location: URL, and data: Data) async throws {
|
||||||
|
// GIVEN
|
||||||
|
let service = service(action: .createFile(location, data))
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
try await service.createFile(at: location, with: data)
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
#expect(spy.actions.count == 1)
|
||||||
|
|
||||||
|
let action = try #require(spy.actions.last)
|
||||||
|
|
||||||
|
#expect(action == .fileCreated(location, data))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(arguments: [FileServiceError.itemAlreadyExists, .fileDataIsEmpty, .fileNotCreated])
|
||||||
|
func createFile(throws error: FileServiceError) async throws {
|
||||||
|
// GIVEN
|
||||||
|
let service = service(action: .error(error))
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
// THEN
|
||||||
|
await #expect(throws: error) {
|
||||||
|
try await service.createFile(at: .someNewFile, with: .init())
|
||||||
|
}
|
||||||
|
|
||||||
|
#expect(spy.actions.isEmpty == true)
|
||||||
|
}
|
||||||
|
|
||||||
@Test(arguments: [URL.someNewFolder, .someNewFile])
|
@Test(arguments: [URL.someNewFolder, .someNewFile])
|
||||||
func createFolder(with location: URL) async throws {
|
func createFolder(with location: URL) async throws {
|
||||||
// GIVEN
|
// GIVEN
|
||||||
|
@ -64,6 +64,19 @@ extension FileServiceMock: FileServicing {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createFile(at location: URL, with data: Data) async throws (FileServiceError) {
|
||||||
|
guard let nextAction else { return }
|
||||||
|
|
||||||
|
switch nextAction {
|
||||||
|
case .error(let error):
|
||||||
|
throw error
|
||||||
|
case let .createFile(location, data):
|
||||||
|
try await spy?.createFile(at: location, with: data)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func createFolder(at location: URL) async throws (FileServiceError) {
|
func createFolder(at location: URL) async throws (FileServiceError) {
|
||||||
guard let nextAction else { return }
|
guard let nextAction else { return }
|
||||||
|
|
||||||
@ -127,6 +140,7 @@ private extension FileServiceMock {
|
|||||||
extension FileServiceMock {
|
extension FileServiceMock {
|
||||||
enum Action {
|
enum Action {
|
||||||
case copyFile(URL, URL)
|
case copyFile(URL, URL)
|
||||||
|
case createFile(URL, Data)
|
||||||
case createFolder(URL)
|
case createFolder(URL)
|
||||||
case deleteItem(URL)
|
case deleteItem(URL)
|
||||||
case error(FileServiceError)
|
case error(FileServiceError)
|
||||||
|
@ -21,6 +21,10 @@ extension FileServiceSpy: FileServicing {
|
|||||||
actions.append(.fileCopied(source, destination))
|
actions.append(.fileCopied(source, destination))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createFile(at location: URL, with data: Data) async throws (FileServiceError) {
|
||||||
|
actions.append(.fileCreated(location, data))
|
||||||
|
}
|
||||||
|
|
||||||
func createFolder(at location: URL) async throws (FileServiceError) {
|
func createFolder(at location: URL) async throws (FileServiceError) {
|
||||||
actions.append(.folderCreated(location))
|
actions.append(.folderCreated(location))
|
||||||
}
|
}
|
||||||
@ -42,6 +46,7 @@ extension FileServiceSpy: FileServicing {
|
|||||||
|
|
||||||
extension FileServiceSpy {
|
extension FileServiceSpy {
|
||||||
enum Action: Equatable {
|
enum Action: Equatable {
|
||||||
|
case fileCreated(_ location: URL, _ data: Data)
|
||||||
case fileCopied(_ source: URL, _ destination: URL)
|
case fileCopied(_ source: URL, _ destination: URL)
|
||||||
case folderCreated(_ location: URL)
|
case folderCreated(_ location: URL)
|
||||||
case itemDeleted(_ location: URL)
|
case itemDeleted(_ location: URL)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user