@_spi(Internal) import ConfigurationClient import Foundation import Testing import TestSupport @Suite("ConfigurationClientTests") struct ConfigurationClientTests: TestCase { @Test func sanity() { withTestLogger(key: "sanity") { @Dependency(\.logger) var logger logger.debug("Testing sanity.") #expect(Bool(true)) } } @Test(arguments: ["config.toml", "config.json"]) func generateConfigFile(fileName: String) async throws { try await withTestLogger(key: "generateConfigFile") { $0.fileClient = .liveValue } operation: { @Dependency(\.logger) var logger @Dependency(\.fileClient) var fileClient let configuration = ConfigurationClient.liveValue try await withTemporaryDirectory { tempDir in let tempFile = tempDir.appending(path: fileName) try await configuration.generate(at: File(tempFile)!, force: false) #expect(FileManager.default.fileExists(atPath: tempFile.cleanFilePath)) #expect(fileClient.fileExists(tempFile)) // Ensure that we do not overwrite files if they exist. do { try await configuration.generate(at: File(tempFile)!, force: false) #expect(Bool(false)) } catch { #expect(Bool(true)) } } } } @Test(arguments: ["config.toml", "config.json", nil]) func loadConfigFile(fileName: String?) async throws { try await withTestLogger(key: "generateConfigFile") { $0.fileClient = .liveValue } operation: { @Dependency(\.logger) var logger @Dependency(\.fileClient) var fileClient let configuration = ConfigurationClient.liveValue guard let fileName else { let loaded = try await configuration.load(nil) #expect(loaded == .init()) return } try await withGeneratedConfigFile(named: fileName, client: configuration) { file in let loaded = try await configuration.load(file) #expect(loaded == .mock) } } } @Test(arguments: ["config.toml", "config.json", ".hparc.json", ".hparc.toml"]) func findConfiguration(fileName: String) async throws { try await withTestLogger(key: "findConfiguration") { $0.fileClient = .liveValue } operation: { @Dependency(\.logger) var logger @Dependency(\.fileClient) var fileClient let client = ConfigurationClient.liveValue try await withGeneratedConfigFile(named: fileName, client: client) { file in for environment in generateFindEnvironments(file: file) { if let home = environment["HOME"] { try await withDependencies { $0.fileClient.homeDirectory = { URL(filePath: home) } } operation: { let configuration = ConfigurationClient.live(environment: environment) let found = try await configuration.find() #expect(found == file) } } else { let configuration = ConfigurationClient.live(environment: environment) let found = try await configuration.find() #expect(found == file) } } } } } @Test(arguments: ["config.toml", "config.json", ".hparc.json", ".hparc.toml"]) func findXdgConfiguration(fileName: String) async throws { try await withTestLogger(key: "findXdgConfiguration") { $0.fileClient = .liveValue } operation: { @Dependency(\.logger) var logger @Dependency(\.fileClient) var fileClient let client = ConfigurationClient.liveValue try await withGeneratedXDGConfigFile(named: fileName, client: client) { file, xdgDir in let environment = ["XDG_CONFIG_HOME": xdgDir.cleanFilePath] let configuration = ConfigurationClient.live(environment: environment) let found = try await configuration.find() #expect(found == file) } } } @Test func testFailingFind() async { await withTestLogger(key: "testFailingFind") { $0.fileClient = .liveValue } operation: { await withTemporaryDirectory { tempDir in let environment = [ "PWD": tempDir.cleanFilePath, "HPA_CONFIG_HOME": tempDir.cleanFilePath ] let configuration = ConfigurationClient.live(environment: environment) do { _ = try await configuration.find() #expect(Bool(false)) } catch { #expect(Bool(true)) } } } } } func generateFindEnvironments(file: File) -> [[String: String]] { let directory = file.url.deletingLastPathComponent().cleanFilePath return [ ["PWD": directory], ["HPA_CONFIG_HOME": directory], ["HPA_CONFIG_FILE": file.path], ["HOME": directory] ] } func withGeneratedConfigFile( named fileName: String, client: ConfigurationClient, _ operation: @Sendable (File) async throws -> Void ) async rethrows { try await withTemporaryDirectory { tempDir in let file = File(tempDir.appending(path: fileName))! try await client.generate(at: file) try await operation(file) } } func withGeneratedXDGConfigFile( named fileName: String, client: ConfigurationClient, _ operation: @Sendable (File, URL) async throws -> Void ) async rethrows { try await withTemporaryDirectory { tempDir in let xdgDir = tempDir.appending(path: HPAKey.configDirName) try FileManager.default.createDirectory( atPath: xdgDir.cleanFilePath, withIntermediateDirectories: false ) let file = File(xdgDir.appending(path: fileName))! try await client.generate(at: file) try await operation(file, tempDir) } }