157 lines
7.3 KiB
Swift
157 lines
7.3 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import CodexBarCore
|
|
|
|
struct ClaudeProbeWorkingDirectoryTests {
|
|
@Test
|
|
func `probe working directory disables deep link registration`() throws {
|
|
let directory = try Self.makeTemporaryDirectory()
|
|
|
|
try ClaudeStatusProbe.prepareProbeWorkingDirectory(at: directory)
|
|
|
|
let settings = try Self.readSettings(from: directory)
|
|
#expect(settings["disableDeepLinkRegistration"] as? String == "disable")
|
|
}
|
|
|
|
@Test
|
|
func `probe working directory preserves existing local settings`() throws {
|
|
let directory = try Self.makeTemporaryDirectory()
|
|
let settingsURL = directory
|
|
.appendingPathComponent(".claude", isDirectory: true)
|
|
.appendingPathComponent("settings.local.json")
|
|
try FileManager.default.createDirectory(
|
|
at: settingsURL.deletingLastPathComponent(),
|
|
withIntermediateDirectories: true)
|
|
let existing: [String: Any] = [
|
|
"permissions": [
|
|
"allow": ["Bash(*)"],
|
|
],
|
|
]
|
|
let data = try JSONSerialization.data(withJSONObject: existing)
|
|
try data.write(to: settingsURL)
|
|
|
|
try ClaudeStatusProbe.prepareProbeWorkingDirectory(at: directory)
|
|
|
|
let settings = try Self.readSettings(from: directory)
|
|
#expect(settings["disableDeepLinkRegistration"] as? String == "disable")
|
|
let permissions = try #require(settings["permissions"] as? [String: Any])
|
|
#expect(permissions["allow"] as? [String] == ["Bash(*)"])
|
|
}
|
|
|
|
@Test
|
|
func `probe working directory overwrites invalid local settings`() throws {
|
|
let directory = try Self.makeTemporaryDirectory()
|
|
let settingsURL = directory
|
|
.appendingPathComponent(".claude", isDirectory: true)
|
|
.appendingPathComponent("settings.local.json")
|
|
try FileManager.default.createDirectory(
|
|
at: settingsURL.deletingLastPathComponent(),
|
|
withIntermediateDirectories: true)
|
|
try Data("{".utf8).write(to: settingsURL)
|
|
|
|
try ClaudeStatusProbe.prepareProbeWorkingDirectory(at: directory)
|
|
|
|
let settings = try Self.readSettings(from: directory)
|
|
#expect(settings["disableDeepLinkRegistration"] as? String == "disable")
|
|
}
|
|
|
|
@Test
|
|
func `probe project directory name matches Claude Code encoding`() {
|
|
let cases = [
|
|
(
|
|
"/Users/test/Library/Application Support/CodexBar/ClaudeProbe",
|
|
"-Users-test-Library-Application-Support-CodexBar-ClaudeProbe"),
|
|
(
|
|
"/Users/test.name/t\u{00E9}st_under/Library/Application Support/CodexBar/ClaudeProbe",
|
|
"-Users-test-name-t-st-under-Library-Application-Support-CodexBar-ClaudeProbe"),
|
|
(
|
|
"/Users/test/emoji_😀/ClaudeProbe",
|
|
"-Users-test-emoji----ClaudeProbe"),
|
|
(
|
|
"/tmp/\(String(repeating: "segment_", count: 40))/ClaudeProbe",
|
|
"-tmp-segment-segment-segment-segment-segment-segment-segment-segment-segment-segment-segment-" +
|
|
"segment-segment-segment-segment-segment-segment-segment-segment-segment-segment-segment-" +
|
|
"segment-segment-seg-x9mpdi"),
|
|
]
|
|
|
|
for (path, expected) in cases {
|
|
let directory = URL(fileURLWithPath: path)
|
|
#expect(ClaudeProbeSessionArtifactCleaner.claudeProjectDirectoryName(for: directory) == expected)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
func `cleanup removes only probe session jsonl artifacts`() throws {
|
|
let probeDirectory = try Self.makeTemporaryDirectory()
|
|
let claudeRoot = try Self.makeTemporaryDirectory()
|
|
let projectsRoot = claudeRoot.appendingPathComponent("projects", isDirectory: true)
|
|
let probeProject = projectsRoot
|
|
.appendingPathComponent(
|
|
ClaudeProbeSessionArtifactCleaner.claudeProjectDirectoryName(for: probeDirectory),
|
|
isDirectory: true)
|
|
let unrelatedProject = projectsRoot.appendingPathComponent("unrelated-project", isDirectory: true)
|
|
try FileManager.default.createDirectory(at: probeProject, withIntermediateDirectories: true)
|
|
try FileManager.default.createDirectory(at: unrelatedProject, withIntermediateDirectories: true)
|
|
defer {
|
|
try? FileManager.default.removeItem(at: probeDirectory)
|
|
try? FileManager.default.removeItem(at: claudeRoot)
|
|
}
|
|
|
|
let probeSession = probeProject.appendingPathComponent("probe-session.jsonl")
|
|
let probeNote = probeProject.appendingPathComponent("keep.txt")
|
|
let unrelatedSession = unrelatedProject.appendingPathComponent("user-session.jsonl")
|
|
try Data("{}\n".utf8).write(to: probeSession)
|
|
try Data("keep".utf8).write(to: probeNote)
|
|
try Data("{}\n".utf8).write(to: unrelatedSession)
|
|
|
|
let removed = ClaudeProbeSessionArtifactCleaner.cleanupProbeSessionArtifacts(
|
|
probeDirectory: probeDirectory,
|
|
environment: ["CLAUDE_CONFIG_DIR": claudeRoot.path, "HOME": claudeRoot.path])
|
|
|
|
#expect(removed.map(\.lastPathComponent) == ["probe-session.jsonl"])
|
|
#expect(!FileManager.default.fileExists(atPath: probeSession.path))
|
|
#expect(FileManager.default.fileExists(atPath: probeNote.path))
|
|
#expect(FileManager.default.fileExists(atPath: unrelatedSession.path))
|
|
}
|
|
|
|
@Test
|
|
func `cleanup removes hashed long probe project artifacts`() throws {
|
|
let probeDirectory = URL(fileURLWithPath: "/tmp/\(String(repeating: "segment_", count: 40))/ClaudeProbe")
|
|
let claudeRoot = try Self.makeTemporaryDirectory()
|
|
let projectsRoot = claudeRoot.appendingPathComponent("projects", isDirectory: true)
|
|
let probeProject = projectsRoot
|
|
.appendingPathComponent(
|
|
ClaudeProbeSessionArtifactCleaner.claudeProjectDirectoryName(for: probeDirectory),
|
|
isDirectory: true)
|
|
try FileManager.default.createDirectory(at: probeProject, withIntermediateDirectories: true)
|
|
defer {
|
|
try? FileManager.default.removeItem(at: claudeRoot)
|
|
}
|
|
|
|
let probeSession = probeProject.appendingPathComponent("probe-session.jsonl")
|
|
try Data("{}\n".utf8).write(to: probeSession)
|
|
|
|
let removed = ClaudeProbeSessionArtifactCleaner.cleanupProbeSessionArtifacts(
|
|
probeDirectory: probeDirectory,
|
|
environment: ["CLAUDE_CONFIG_DIR": claudeRoot.path, "HOME": claudeRoot.path])
|
|
|
|
#expect(removed.map(\.lastPathComponent) == ["probe-session.jsonl"])
|
|
#expect(!FileManager.default.fileExists(atPath: probeSession.path))
|
|
}
|
|
|
|
private static func makeTemporaryDirectory() throws -> URL {
|
|
let directory = FileManager.default.temporaryDirectory
|
|
.appendingPathComponent("codexbar-claude-probe-\(UUID().uuidString)", isDirectory: true)
|
|
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
|
|
return directory
|
|
}
|
|
|
|
private static func readSettings(from directory: URL) throws -> [String: Any] {
|
|
let settingsURL = directory
|
|
.appendingPathComponent(".claude", isDirectory: true)
|
|
.appendingPathComponent("settings.local.json")
|
|
let data = try Data(contentsOf: settingsURL)
|
|
return try #require(JSONSerialization.jsonObject(with: data) as? [String: Any])
|
|
}
|
|
}
|