diff --git a/Sources/hexcode/Commands/Hexcode.swift b/Sources/hexcode/Commands/Hexcode.swift index b1e8f9d..3a4fbc0 100644 --- a/Sources/hexcode/Commands/Hexcode.swift +++ b/Sources/hexcode/Commands/Hexcode.swift @@ -10,7 +10,7 @@ struct Hexcode: AsyncParsableCommand { by their hexadecimal codes. """, usage: "hexcode [--directory ]", - version: "hexcode 0.2.0", + version: "hexcode 0.2.1", subcommands: [ FindColor.self, FindDuplicates.self, diff --git a/Sources/hexcode/HexcodeApp.swift b/Sources/hexcode/HexcodeApp.swift index b2694fb..eaae35d 100644 --- a/Sources/hexcode/HexcodeApp.swift +++ b/Sources/hexcode/HexcodeApp.swift @@ -27,7 +27,7 @@ final class HexcodeApp { /// - directory: Optional custom directory from user input. Defaults to current directory. /// - throws: All unhandled errors that can be thrown out to standard output. func runFindColor(colorHex: String, in directory: String? = nil) async throws { - let directory = directory ?? fileManager.currentDirectoryPath + let directory = directory.map(expandTilde) ?? fileManager.currentDirectoryPath let colorAssets = try await assetCollector.collectAssets(in: directory) let foundColors = colorFinder.find(colorHex, in: colorAssets) @@ -39,12 +39,11 @@ final class HexcodeApp { foundColors.forEach { output($0) } } - /// Entry point for the `find-duplicates` subcommand logic. /// - Parameter directory: Optional custom directory from user input. Defaults to current directory. /// - throws: All unhandled errors that can be thrown out to standard output. func runFindDuplicates(in directory: String? = nil) async throws { - let directory = directory ?? fileManager.currentDirectoryPath + let directory = directory.map(expandTilde) ?? fileManager.currentDirectoryPath let colorAssets = try await assetCollector.collectAssets(in: directory) let foundDuplicates = colorFinder.findDuplicates(in: colorAssets) @@ -72,3 +71,14 @@ final class HexcodeApp { } } } + +// MARK: - Private + +extension HexcodeApp { + private func expandTilde(_ path: String) -> String { + path.replacingOccurrences( + of: "~", + with: fileManager.homeDirectoryForCurrentUser.relativePath + ) + } +} diff --git a/Tests/hexcodeTests/HexcodeAppTests.swift b/Tests/hexcodeTests/HexcodeAppTests.swift index cc103dd..6eb53f7 100644 --- a/Tests/hexcodeTests/HexcodeAppTests.swift +++ b/Tests/hexcodeTests/HexcodeAppTests.swift @@ -175,6 +175,25 @@ final class HexcodeAppTests: XCTestCase { XCTAssertEqual(mocks.outputs, ["No \(blackHexStub) color found"]) } + func test_runFindColor_withTildeInPath_expandsTildaToFilePath() async throws { + // Given + let homeDir = "/home/dir" + let homeURL = try XCTUnwrap(URL(filePath: homeDir)) + mocks.fileManager.results.homeDirectoryForCurrentUser = homeURL + + // When + try await sut.runFindColor(colorHex: blackHexStub, in: "~/TestProject") + + + // Then + XCTAssertEqual(mocks.fileManager.calls, [ + .getHomeDirectoryForCurrentUser + ]) + XCTAssertEqual(mocks.assetCollector.calls, [ + .collectAssetsIn(directory: "\(homeDir)/TestProject") + ]) + } + // MARK: Test runFindDuplicates func test_runFindDuplicates_whenSingleDuplicateFound_outputsDuplicateHexAndAssetNames() async throws { @@ -226,6 +245,25 @@ final class HexcodeAppTests: XCTestCase { "#FFFFFF text (Any, Light)", ]) } + + func test_runFindDuplicates_withTildeInPath_expandsTildaToFilePath() async throws { + // Given + let homeDir = "/Users/user" + let homeURL = try XCTUnwrap(URL(string: homeDir)) + mocks.fileManager.results.homeDirectoryForCurrentUser = homeURL + + // When + try await sut.runFindDuplicates(in: "~/documents/project") + + + // Then + XCTAssertEqual(mocks.fileManager.calls, [ + .getHomeDirectoryForCurrentUser + ]) + XCTAssertEqual(mocks.assetCollector.calls, [ + .collectAssetsIn(directory: "\(homeDir)/documents/project") + ]) + } } // MARK: - Private diff --git a/Tests/hexcodeTests/Mocks/FileManagerMock.swift b/Tests/hexcodeTests/Mocks/FileManagerMock.swift index 0c94562..7cd3b04 100644 --- a/Tests/hexcodeTests/Mocks/FileManagerMock.swift +++ b/Tests/hexcodeTests/Mocks/FileManagerMock.swift @@ -10,6 +10,7 @@ final class FileManagerMock: FileManager { enum Call: Equatable { case getCurrentDirectoryPath case setCurrentDirectoryPath(String) + case getHomeDirectoryForCurrentUser case fileExists(path: String, isDirectory: UnsafeMutablePointer?) case contentsOfDirectory(path: String) case contents(path: String) @@ -17,6 +18,7 @@ final class FileManagerMock: FileManager { struct CallResults { var currentDirectoryPath: String = "" + var homeDirectoryForCurrentUser: URL = .init(filePath: "") var fileExistsAtPath: [String: PathContent] = [:] var contentsOfDirectory: [String: Result<[String], Error>] = [:] var contentsAtPath: [String: Data] = [:] @@ -60,6 +62,13 @@ extension FileManagerMock { } } + override var homeDirectoryForCurrentUser: URL { + get { + calls.append(.getHomeDirectoryForCurrentUser) + return results.homeDirectoryForCurrentUser + } + } + override func fileExists(atPath path: String, isDirectory: UnsafeMutablePointer?) -> Bool { calls.append(.fileExists(path: path, isDirectory: isDirectory)) guard let pathContent = results.fileExistsAtPath[path] else { return false }