119 lines
4.5 KiB
Swift
119 lines
4.5 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import CodexBarCore
|
|
|
|
struct ClaudeSourcePlannerTests {
|
|
@Test
|
|
func `app auto plan preserves ordered steps and reasons`() {
|
|
let plan = ClaudeSourcePlanner.resolve(input: ClaudeSourcePlanningInput(
|
|
runtime: .app,
|
|
selectedDataSource: .auto,
|
|
webExtrasEnabled: false,
|
|
hasWebSession: true,
|
|
hasCLI: true,
|
|
hasOAuthCredentials: true))
|
|
|
|
#expect(plan.orderedSteps.map(\.dataSource) == [.oauth, .cli, .web])
|
|
#expect(plan.orderedSteps.map(\.inclusionReason) == [
|
|
.appAutoPreferredOAuth,
|
|
.appAutoFallbackCLI,
|
|
.appAutoFallbackWeb,
|
|
])
|
|
#expect(plan.availableSteps.map(\.dataSource) == [.oauth, .cli, .web])
|
|
#expect(plan.preferredStep?.dataSource == .oauth)
|
|
}
|
|
|
|
@Test
|
|
func `CLI auto plan preserves ordered steps and reasons`() {
|
|
let plan = ClaudeSourcePlanner.resolve(input: ClaudeSourcePlanningInput(
|
|
runtime: .cli,
|
|
selectedDataSource: .auto,
|
|
webExtrasEnabled: false,
|
|
hasWebSession: true,
|
|
hasCLI: true,
|
|
hasOAuthCredentials: false))
|
|
|
|
#expect(plan.orderedSteps.map(\.dataSource) == [.web, .cli])
|
|
#expect(plan.orderedSteps.map(\.inclusionReason) == [
|
|
.cliAutoPreferredWeb,
|
|
.cliAutoFallbackCLI,
|
|
])
|
|
#expect(plan.preferredStep?.dataSource == .web)
|
|
}
|
|
|
|
@Test
|
|
func `explicit mode plan is single step`() {
|
|
let plan = ClaudeSourcePlanner.resolve(input: ClaudeSourcePlanningInput(
|
|
runtime: .app,
|
|
selectedDataSource: .cli,
|
|
webExtrasEnabled: true,
|
|
hasWebSession: false,
|
|
hasCLI: true,
|
|
hasOAuthCredentials: false))
|
|
|
|
#expect(plan.orderedSteps.count == 1)
|
|
#expect(plan.orderedSteps.first?.dataSource == .cli)
|
|
#expect(plan.orderedSteps.first?.inclusionReason == .explicitSourceSelection)
|
|
#expect(plan.compatibilityStrategy == ClaudeUsageStrategy(dataSource: .cli, useWebExtras: true))
|
|
}
|
|
|
|
@Test
|
|
func `app auto CLI fallback reports web extras like runtime`() {
|
|
let plan = ClaudeSourcePlanner.resolve(input: ClaudeSourcePlanningInput(
|
|
runtime: .app,
|
|
selectedDataSource: .auto,
|
|
webExtrasEnabled: true,
|
|
hasWebSession: false,
|
|
hasCLI: true,
|
|
hasOAuthCredentials: false))
|
|
|
|
#expect(plan.preferredStep?.dataSource == .cli)
|
|
#expect(plan.compatibilityStrategy == ClaudeUsageStrategy(dataSource: .cli, useWebExtras: true))
|
|
}
|
|
|
|
@Test
|
|
func `no source planner output is deterministic`() {
|
|
let input = ClaudeSourcePlanningInput(
|
|
runtime: .app,
|
|
selectedDataSource: .auto,
|
|
webExtrasEnabled: false,
|
|
hasWebSession: false,
|
|
hasCLI: false,
|
|
hasOAuthCredentials: false)
|
|
let plan = ClaudeSourcePlanner.resolve(input: input)
|
|
|
|
#expect(plan.orderedSteps.map(\.dataSource) == [.oauth, .cli, .web])
|
|
#expect(plan.availableSteps.isEmpty)
|
|
#expect(plan.isNoSourceAvailable)
|
|
#expect(plan.preferredStep == nil)
|
|
#expect(plan.executionSteps.isEmpty)
|
|
#expect(plan.debugLines() == [
|
|
"planner_order=oauth→cli→web",
|
|
"planner_selected=none",
|
|
"planner_no_source=true",
|
|
"planner_step.oauth=unavailable reason=app-auto-preferred-oauth",
|
|
"planner_step.cli=unavailable reason=app-auto-fallback-cli",
|
|
"planner_step.web=unavailable reason=app-auto-fallback-web",
|
|
])
|
|
}
|
|
|
|
@Test
|
|
func `CLI resolver falls back to PATH when Claude CLI path override is invalid`() throws {
|
|
let tempDir = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent(UUID().uuidString, isDirectory: true)
|
|
try FileManager.default.createDirectory(at: tempDir, withIntermediateDirectories: true)
|
|
let binaryURL = tempDir.appendingPathComponent("claude")
|
|
try Data("#!/bin/sh\nexit 0\n".utf8).write(to: binaryURL)
|
|
try FileManager.default.setAttributes([.posixPermissions: 0o755], ofItemAtPath: binaryURL.path)
|
|
|
|
let resolved = ClaudeCLIResolver.resolvedBinaryPath(
|
|
environment: [
|
|
"CLAUDE_CLI_PATH": "/definitely/missing/claude",
|
|
"PATH": tempDir.path,
|
|
],
|
|
loginPATH: nil)
|
|
|
|
#expect(resolved == binaryURL.path)
|
|
}
|
|
}
|