From f8f4f249a3ef12dcf988f31c8ebb8f35a85c5419 Mon Sep 17 00:00:00 2001 From: Vitalii Budnik Date: Wed, 25 Jun 2025 17:48:05 +0300 Subject: [PATCH] chore: update file manager protocol --- ...inaryDependenciesConfigurationReader.swift | 4 +-- .../Utils/FileManagerProtocol.swift | 36 +++++++++++++++++++ ...DependenciesConfigurationReaderTests.swift | 10 +++--- .../CLITests.swift | 2 +- .../Mocks/FileManagerProtocolMock.swift | 35 ++++++++++++++++-- 5 files changed, 78 insertions(+), 9 deletions(-) diff --git a/Sources/BinaryDependencyManager/Utils/BinaryDependenciesConfigurationReader.swift b/Sources/BinaryDependencyManager/Utils/BinaryDependenciesConfigurationReader.swift index 5f557f5..e5ad58a 100644 --- a/Sources/BinaryDependencyManager/Utils/BinaryDependenciesConfigurationReader.swift +++ b/Sources/BinaryDependencyManager/Utils/BinaryDependenciesConfigurationReader.swift @@ -51,7 +51,7 @@ public struct BinaryDependenciesConfigurationReader { /// - Returns: The resolved configuration file URL. public func resolveConfigurationFileURL(_ configurationFilePath: String?) throws -> URL { let configurationFileURL = resolveFilePath(configurationFilePath, variations: Self.defaultConfigurationFilenames) - guard fileManager.fileExists(atPath: configurationFileURL.path) else { + guard fileManager.fileExists(at: configurationFileURL) else { throw GenericError("No configuration file found") } return configurationFileURL @@ -85,8 +85,8 @@ public struct BinaryDependenciesConfigurationReader { let configurationURL: URL = try resolveConfigurationFileURL(configurationPath) // Get the contents of the file - guard let dependenciesData: Data = fileManager.contents(atPath: configurationURL.path) else { throw GenericError("Can't get contents of configuration file at \(configurationURL.path)") + guard let dependenciesData: Data = fileManager.contents(at: configurationURL) else { } // Decoder selection: Check if this is yaml, and fallback to JSONDecoder. diff --git a/Sources/BinaryDependencyManager/Utils/FileManagerProtocol.swift b/Sources/BinaryDependencyManager/Utils/FileManagerProtocol.swift index 50e2fa6..362c27a 100644 --- a/Sources/BinaryDependencyManager/Utils/FileManagerProtocol.swift +++ b/Sources/BinaryDependencyManager/Utils/FileManagerProtocol.swift @@ -13,6 +13,42 @@ public protocol FileManagerProtocol { /// - path: The path of the file whose contents you want. /// - Returns: An `Data` object with the contents of the file. If path specifies a directory, or if some other error occurs, this method returns nil. func contents(atPath path: String) -> Data? + + /// The temporary directory for the current user. + var temporaryDirectory: URL { get } + + /// Removes the file or directory at the specified path. + /// - Parameters: + /// - url: A file URL specifying the file or directory to remove. If the URL specifies a directory, the contents of that directory are recursively removed. + func removeItem(at url: URL) throws + + func createDirectory(at url: URL, withIntermediateDirectories createIntermediates: Bool, attributes: [FileAttributeKey : Any]?) throws + + func contentsOfDirectory(atPath path: String) throws -> [String] + + func createFile(atPath path: String, contents data: Data?, attributes attr: [FileAttributeKey : Any]?) -> Bool +} + +extension FileManagerProtocol { + public func createDirectory(at url: URL, withIntermediateDirectories createIntermediates: Bool) throws { + try createDirectory(at: url, withIntermediateDirectories: createIntermediates, attributes: .none) + } + + public func fileExists(at url: URL) -> Bool { + fileExists(atPath: url.filePath) + } + + public func contents(at url: URL) -> Data? { + contents(atPath: url.filePath) + } + + public func contentsOfDirectory(at url: URL) throws -> [String] { + try contentsOfDirectory(atPath: url.filePath) + } + + func createFile(at url: URL, contents data: Data?) -> Bool { + createFile(atPath: url.filePath, contents: data, attributes: .none) + } } extension FileManager: FileManagerProtocol {} diff --git a/Tests/BinaryDependencyManagerTests/BinaryDependenciesConfigurationReaderTests.swift b/Tests/BinaryDependencyManagerTests/BinaryDependenciesConfigurationReaderTests.swift index 3e8851e..3d3c7d4 100644 --- a/Tests/BinaryDependencyManagerTests/BinaryDependenciesConfigurationReaderTests.swift +++ b/Tests/BinaryDependencyManagerTests/BinaryDependenciesConfigurationReaderTests.swift @@ -3,11 +3,12 @@ import XCTest import Testing import Yams import Foundation +import Utils final class BinaryDependenciesConfigurationReaderTests: XCTestCase { private func makeReader(withFiles files: [String]) -> BinaryDependenciesConfigurationReader { let mockFileManager = FileManagerProtocolMock() - mockFileManager.files = Set(files) + mockFileManager.existingFiles = Set(files) return BinaryDependenciesConfigurationReader(fileManager: mockFileManager) } @@ -15,10 +16,11 @@ final class BinaryDependenciesConfigurationReaderTests: XCTestCase { let sut = makeReader(withFiles: ["/the/path/.binary-dependencies.yaml"]) let url = try sut.resolveConfigurationFileURL("/the/path/.binary-dependencies.yaml") XCTAssertEqual(url.path, "/the/path/.binary-dependencies.yaml") + XCTAssertEqual(url.filePath, "/the/path/.binary-dependencies.yaml") } func test_resolveConfigurationFileURL_fallbackToDefault() throws { - let sut = makeReader(withFiles: [".binary-dependencies.yaml".asFileURL.path]) + let sut = makeReader(withFiles: [".binary-dependencies.yaml".asFileURL.filePath]) let url = try sut.resolveConfigurationFileURL(nil) XCTAssertEqual(url.lastPathComponent, ".binary-dependencies.yaml") } @@ -52,10 +54,10 @@ final class BinaryDependenciesConfigurationReaderTests: XCTestCase { pattern: pattern1 checksum: "check1" """ - let filePath = ".binary-dependencies.yaml".asFileURL.path + let filePath = ".binary-dependencies.yaml".asFileURL.filePath let data = Data(yamlString.utf8) let mockFileManager = FileManagerProtocolMock() - mockFileManager.files = [filePath] + mockFileManager.existingFiles = [filePath] mockFileManager.contents = [filePath: data] let sut = BinaryDependenciesConfigurationReader(fileManager: mockFileManager) diff --git a/Tests/BinaryDependencyManagerTests/CLITests.swift b/Tests/BinaryDependencyManagerTests/CLITests.swift index b33932f..6a1ea3f 100644 --- a/Tests/BinaryDependencyManagerTests/CLITests.swift +++ b/Tests/BinaryDependencyManagerTests/CLITests.swift @@ -1,5 +1,5 @@ import XCTest -@testable import binary_dependencies_manager +@testable import Utils final class CLITests: XCTestCase { func testWhichFindsExistingTool() throws { diff --git a/Tests/BinaryDependencyManagerTests/Mocks/FileManagerProtocolMock.swift b/Tests/BinaryDependencyManagerTests/Mocks/FileManagerProtocolMock.swift index 17dc8b7..3cd9206 100644 --- a/Tests/BinaryDependencyManagerTests/Mocks/FileManagerProtocolMock.swift +++ b/Tests/BinaryDependencyManagerTests/Mocks/FileManagerProtocolMock.swift @@ -2,13 +2,44 @@ import Foundation class FileManagerProtocolMock: FileManagerProtocol { - var files: Set = [] + func createDirectory(at url: URL, withIntermediateDirectories createIntermediates: Bool, attributes: [FileAttributeKey : Any]?) throws { + createdDirectories.append(url) + } + + func contentsOfDirectory(atPath path: String) throws -> [String] { + [] + } + + var existingFiles: Set = [] func fileExists(atPath path: String) -> Bool { - files.contains(path) + existingFiles.contains(path) } var contents: [String: Data] = [:] func contents(atPath path: String) -> Data? { contents[path] } + + var createdDirectories: [URL] = [] + var contentsMap: [URL: Data] = [:] + var removedItems: [URL] = [] + var tempDir: URL + + init(tempDir: URL = URL(fileURLWithPath: "/tmp/mock")) { + self.tempDir = tempDir + } + + var temporaryDirectory: URL { tempDir } + func contents(at url: URL) -> Data? { contentsMap[url] } + func removeItem(at url: URL) throws { removedItems.append(url) } + + var createdFiles: [String] = [] + func createFile(atPath path: String, contents data: Data?, attributes attr: [FileAttributeKey : Any]?) -> Bool { + guard !createdFiles.contains(path) else { return false } + + createdFiles.append(path) + contents[path] = data + + return true + } }