import CodexBarCoreimport Foundationimport Testing struct ConfigValidationTests { @Test func `reports unsupported source`() { var config = CodexBarConfig.makeDefault() config.setProviderConfig(ProviderConfig(id: .codex, source: .api)) let issues = CodexBarConfigValidator.validate(config) #expect(issues.contains(where: { $0.code == "unsupported_source" })) } @Test func `reports missing API key when source API`() { var config = CodexBarConfig.makeDefault() config.setProviderConfig(ProviderConfig(id: .zai, source: .api, apiKey: nil)) let issues = CodexBarConfigValidator.validate(config) #expect(issues.contains(where: { $0.code == "api_key_missing" })) } @Test func `reports invalid region`() { var config = CodexBarConfig.makeDefault() config.setProviderConfig(ProviderConfig(id: .minimax, region: "nowhere")) let issues = CodexBarConfigValidator.validate(config) #expect(issues.contains(where: { $0.code == "invalid_region" })) } @Test func `warns on unsupported token accounts`() { let accounts = ProviderTokenAccountData( version: 1, accounts: [ProviderTokenAccount(id: UUID(), label: "a", token: "t", addedAt: 0, lastUsed: nil)], activeIndex: 0) var config = CodexBarConfig.makeDefault() config.setProviderConfig(ProviderConfig(id: .gemini, tokenAccounts: accounts)) let issues = CodexBarConfigValidator.validate(config) #expect(issues.contains(where: { $0.code == "token_accounts_unused" })) } @Test func `allows ollama token accounts`() { let accounts = ProviderTokenAccountData( version: 1, accounts: [ProviderTokenAccount(id: UUID(), label: "a", token: "t", addedAt: 0, lastUsed: nil)], activeIndex: 0) var config = CodexBarConfig.makeDefault() config.setProviderConfig(ProviderConfig(id: .ollama, tokenAccounts: accounts)) let issues = CodexBarConfigValidator.validate(config) #expect(!issues.contains(where: { $0.code == "token_accounts_unused" && $0.provider == .ollama })) } @Test func `accepts kilo extras config field`() { var config = CodexBarConfig.makeDefault() config.setProviderConfig(ProviderConfig(id: .kilo, extrasEnabled: true)) let issues = CodexBarConfigValidator.validate(config) #expect(!issues.contains(where: { $0.provider == .kilo && $0.field == "extrasEnabled" })) } @Test func `allows deepgram project workspace ID`() { var config = CodexBarConfig.makeDefault() config.setProviderConfig(ProviderConfig(id: .deepgram, workspaceID: "project-123")) let issues = CodexBarConfigValidator.validate(config) #expect(!issues.contains(where: { $0.provider == .deepgram && $0.code == "workspace_unused" })) } @Test func `allows Azure OpenAI endpoint and deployment fields`() { var config = CodexBarConfig.makeDefault() config.setProviderConfig(ProviderConfig( id: .azureopenai, workspaceID: "chat-prod", enterpriseHost: "https://example-resource.openai.azure.com")) let issues = CodexBarConfigValidator.validate(config) #expect(!issues.contains(where: { $0.provider == .azureopenai && $0.code == "workspace_unused" })) #expect(!issues.contains(where: { $0.provider == .azureopenai && $0.code == "enterprise_host_unused" })) } @Test func `allows LiteLLM endpoint`() { var config = CodexBarConfig.makeDefault() config.setProviderConfig(ProviderConfig( id: .litellm, apiKey: "sk-test", enterpriseHost: "https://litellm.example.com")) let issues = CodexBarConfigValidator.validate(config) #expect(!issues.contains(where: { $0.provider == .litellm && $0.code == "enterprise_host_unused" })) } @Test func `allows OpenAI API project workspace ID`() { var config = CodexBarConfig.makeDefault() config.setProviderConfig(ProviderConfig(id: .openai, workspaceID: "proj_abc")) let issues = CodexBarConfigValidator.validate(config) #expect(!issues.contains(where: { $0.provider == .openai && $0.code == "workspace_unused" })) } @Test func `warns on unsupported workspace ID`() { var config = CodexBarConfig.makeDefault() config.setProviderConfig(ProviderConfig(id: .gemini, workspaceID: "workspace-123")) let issues = CodexBarConfigValidator.validate(config) #expect(issues.contains(where: { $0.provider == .gemini && $0.code == "workspace_unused" })) #expect(issues.contains(where: { issue in issue.provider == .gemini && issue.code == "workspace_unused" && issue.message.contains("openai") })) } @Test func `config store default url honors environment override`() { let url = CodexBarConfigStore.defaultURL(environment: [ CodexBarConfigStore.pathEnvironmentKey: "~/tmp/codexbar-test-config.json", ]) #expect(url.path.hasSuffix("/tmp/codexbar-test-config.json")) } @Test func `config store default url honors xdg config home`() throws { let fileManager = FileManager.default let home = try Self.makeTemporaryHome() defer { try? fileManager.removeItem(at: home) } let xdgHome = home.appendingPathComponent("custom-config", isDirectory: true) let url = CodexBarConfigStore.defaultURL( home: home, environment: [ CodexBarConfigStore.xdgConfigHomeEnvironmentKey: xdgHome.path, ], fileManager: fileManager) #expect(url == Self.configURL(in: xdgHome)) } @Test func `config store default url ignores relative xdg config home`() throws { let fileManager = FileManager.default let home = try Self.makeTemporaryHome() defer { try? fileManager.removeItem(at: home) } let legacy = Self.legacyConfigURL(in: home) try Self.touch(legacy, fileManager: fileManager) let url = CodexBarConfigStore.defaultURL( home: home, environment: [ CodexBarConfigStore.xdgConfigHomeEnvironmentKey: "relative-config", ], fileManager: fileManager) #expect(url == legacy) } @Test func `config store default url creates in xdg default for new installs`() throws { let fileManager = FileManager.default let home = try Self.makeTemporaryHome() defer { try? fileManager.removeItem(at: home) } let url = CodexBarConfigStore.defaultURL(home: home, environment: [:], fileManager: fileManager) #expect(url == Self.configURL(in: home.appendingPathComponent(".config", isDirectory: true))) } @Test func `config store default url keeps existing legacy config`() throws { let fileManager = FileManager.default let home = try Self.makeTemporaryHome() defer { try? fileManager.removeItem(at: home) } let legacy = Self.legacyConfigURL(in: home) try Self.touch(legacy, fileManager: fileManager) let url = CodexBarConfigStore.defaultURL(home: home, environment: [:], fileManager: fileManager) #expect(url == legacy) } @Test func `config store default url prefers existing xdg default over legacy config`() throws { let fileManager = FileManager.default let home = try Self.makeTemporaryHome() defer { try? fileManager.removeItem(at: home) } let xdgDefault = Self.configURL(in: home.appendingPathComponent(".config", isDirectory: true)) let legacy = Self.legacyConfigURL(in: home) try Self.touch(legacy, fileManager: fileManager) try Self.touch(xdgDefault, fileManager: fileManager) let url = CodexBarConfigStore.defaultURL(home: home, environment: [:], fileManager: fileManager) #expect(url == xdgDefault) } private static func makeTemporaryHome() throws -> URL { let url = FileManager.default.temporaryDirectory .appendingPathComponent("CodexBarConfigStoreTests-\(UUID().uuidString)", isDirectory: true) try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true) return url } private static func touch(_ url: URL, fileManager: FileManager) throws { try fileManager.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true) try Data().write(to: url) } private static func configURL(in directory: URL) -> URL { directory .appendingPathComponent("codexbar", isDirectory: true) .appendingPathComponent("config.json") } private static func legacyConfigURL(in home: URL) -> URL { home .appendingPathComponent(".codexbar", isDirectory: true) .appendingPathComponent("config.json") }}
import CodexBarCore
import Foundation
import Testing
struct ConfigValidationTests {
@Test
func `reports unsupported source`() {
var config = CodexBarConfig.makeDefault()
config.setProviderConfig(ProviderConfig(id: .codex, source: .api))
let issues = CodexBarConfigValidator.validate(config)
#expect(issues.contains(where: { $0.code == "unsupported_source" }))
}
@Test
func `reports missing API key when source API`() {
var config = CodexBarConfig.makeDefault()
config.setProviderConfig(ProviderConfig(id: .zai, source: .api, apiKey: nil))
let issues = CodexBarConfigValidator.validate(config)
#expect(issues.contains(where: { $0.code == "api_key_missing" }))
}
@Test
func `reports invalid region`() {
var config = CodexBarConfig.makeDefault()
config.setProviderConfig(ProviderConfig(id: .minimax, region: "nowhere"))
let issues = CodexBarConfigValidator.validate(config)
#expect(issues.contains(where: { $0.code == "invalid_region" }))
}
@Test
func `warns on unsupported token accounts`() {
let accounts = ProviderTokenAccountData(
version: 1,
accounts: [ProviderTokenAccount(id: UUID(), label: "a", token: "t", addedAt: 0, lastUsed: nil)],
activeIndex: 0)
var config = CodexBarConfig.makeDefault()
config.setProviderConfig(ProviderConfig(id: .gemini, tokenAccounts: accounts))
let issues = CodexBarConfigValidator.validate(config)
#expect(issues.contains(where: { $0.code == "token_accounts_unused" }))
}
@Test
func `allows ollama token accounts`() {
let accounts = ProviderTokenAccountData(
version: 1,
accounts: [ProviderTokenAccount(id: UUID(), label: "a", token: "t", addedAt: 0, lastUsed: nil)],
activeIndex: 0)
var config = CodexBarConfig.makeDefault()
config.setProviderConfig(ProviderConfig(id: .ollama, tokenAccounts: accounts))
let issues = CodexBarConfigValidator.validate(config)
#expect(!issues.contains(where: { $0.code == "token_accounts_unused" && $0.provider == .ollama }))
}
@Test
func `accepts kilo extras config field`() {
var config = CodexBarConfig.makeDefault()
config.setProviderConfig(ProviderConfig(id: .kilo, extrasEnabled: true))
let issues = CodexBarConfigValidator.validate(config)
#expect(!issues.contains(where: { $0.provider == .kilo && $0.field == "extrasEnabled" }))
}
@Test
func `allows deepgram project workspace ID`() {
var config = CodexBarConfig.makeDefault()
config.setProviderConfig(ProviderConfig(id: .deepgram, workspaceID: "project-123"))
let issues = CodexBarConfigValidator.validate(config)
#expect(!issues.contains(where: { $0.provider == .deepgram && $0.code == "workspace_unused" }))
}
@Test
func `allows Azure OpenAI endpoint and deployment fields`() {
var config = CodexBarConfig.makeDefault()
config.setProviderConfig(ProviderConfig(
id: .azureopenai,
workspaceID: "chat-prod",
enterpriseHost: "https://example-resource.openai.azure.com"))
let issues = CodexBarConfigValidator.validate(config)
#expect(!issues.contains(where: { $0.provider == .azureopenai && $0.code == "workspace_unused" }))
#expect(!issues.contains(where: { $0.provider == .azureopenai && $0.code == "enterprise_host_unused" }))
}
@Test
func `allows LiteLLM endpoint`() {
var config = CodexBarConfig.makeDefault()
config.setProviderConfig(ProviderConfig(
id: .litellm,
apiKey: "sk-test",
enterpriseHost: "https://litellm.example.com"))
let issues = CodexBarConfigValidator.validate(config)
#expect(!issues.contains(where: { $0.provider == .litellm && $0.code == "enterprise_host_unused" }))
}
@Test
func `allows OpenAI API project workspace ID`() {
var config = CodexBarConfig.makeDefault()
config.setProviderConfig(ProviderConfig(id: .openai, workspaceID: "proj_abc"))
let issues = CodexBarConfigValidator.validate(config)
#expect(!issues.contains(where: { $0.provider == .openai && $0.code == "workspace_unused" }))
}
@Test
func `warns on unsupported workspace ID`() {
var config = CodexBarConfig.makeDefault()
config.setProviderConfig(ProviderConfig(id: .gemini, workspaceID: "workspace-123"))
let issues = CodexBarConfigValidator.validate(config)
#expect(issues.contains(where: { $0.provider == .gemini && $0.code == "workspace_unused" }))
#expect(issues.contains(where: { issue in
issue.provider == .gemini &&
issue.code == "workspace_unused" &&
issue.message.contains("openai")
}))
}
@Test
func `config store default url honors environment override`() {
let url = CodexBarConfigStore.defaultURL(environment: [
CodexBarConfigStore.pathEnvironmentKey: "~/tmp/codexbar-test-config.json",
])
#expect(url.path.hasSuffix("/tmp/codexbar-test-config.json"))
}
@Test
func `config store default url honors xdg config home`() throws {
let fileManager = FileManager.default
let home = try Self.makeTemporaryHome()
defer { try? fileManager.removeItem(at: home) }
let xdgHome = home.appendingPathComponent("custom-config", isDirectory: true)
let url = CodexBarConfigStore.defaultURL(
home: home,
environment: [
CodexBarConfigStore.xdgConfigHomeEnvironmentKey: xdgHome.path,
],
fileManager: fileManager)
#expect(url == Self.configURL(in: xdgHome))
}
@Test
func `config store default url ignores relative xdg config home`() throws {
let fileManager = FileManager.default
let home = try Self.makeTemporaryHome()
defer { try? fileManager.removeItem(at: home) }
let legacy = Self.legacyConfigURL(in: home)
try Self.touch(legacy, fileManager: fileManager)
let url = CodexBarConfigStore.defaultURL(
home: home,
environment: [
CodexBarConfigStore.xdgConfigHomeEnvironmentKey: "relative-config",
],
fileManager: fileManager)
#expect(url == legacy)
}
@Test
func `config store default url creates in xdg default for new installs`() throws {
let fileManager = FileManager.default
let home = try Self.makeTemporaryHome()
defer { try? fileManager.removeItem(at: home) }
let url = CodexBarConfigStore.defaultURL(home: home, environment: [:], fileManager: fileManager)
#expect(url == Self.configURL(in: home.appendingPathComponent(".config", isDirectory: true)))
}
@Test
func `config store default url keeps existing legacy config`() throws {
let fileManager = FileManager.default
let home = try Self.makeTemporaryHome()
defer { try? fileManager.removeItem(at: home) }
let legacy = Self.legacyConfigURL(in: home)
try Self.touch(legacy, fileManager: fileManager)
let url = CodexBarConfigStore.defaultURL(home: home, environment: [:], fileManager: fileManager)
#expect(url == legacy)
}
@Test
func `config store default url prefers existing xdg default over legacy config`() throws {
let fileManager = FileManager.default
let home = try Self.makeTemporaryHome()
defer { try? fileManager.removeItem(at: home) }
let xdgDefault = Self.configURL(in: home.appendingPathComponent(".config", isDirectory: true))
let legacy = Self.legacyConfigURL(in: home)
try Self.touch(legacy, fileManager: fileManager)
try Self.touch(xdgDefault, fileManager: fileManager)
let url = CodexBarConfigStore.defaultURL(home: home, environment: [:], fileManager: fileManager)
#expect(url == xdgDefault)
}
private static func makeTemporaryHome() throws -> URL {
let url = FileManager.default.temporaryDirectory
.appendingPathComponent("CodexBarConfigStoreTests-\(UUID().uuidString)", isDirectory: true)
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true)
return url
}
private static func touch(_ url: URL, fileManager: FileManager) throws {
try fileManager.createDirectory(at: url.deletingLastPathComponent(), withIntermediateDirectories: true)
try Data().write(to: url)
}
private static func configURL(in directory: URL) -> URL {
directory
.appendingPathComponent("codexbar", isDirectory: true)
.appendingPathComponent("config.json")
}
private static func legacyConfigURL(in home: URL) -> URL {
home
.appendingPathComponent(".codexbar", isDirectory: true)
.appendingPathComponent("config.json")
}
}