102 lines
3.2 KiB
Python
102 lines
3.2 KiB
Python
"""Unit tests for `jsonl_paths` — pure string transforms + light fs lookup."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from claude_code_api.paths import (
|
|
claude_home,
|
|
encode_project_key,
|
|
find_jsonl_by_session_id,
|
|
projects_root,
|
|
resolve_jsonl_path,
|
|
session_dir,
|
|
)
|
|
|
|
# ----- encode_project_key -----------------------------------------------------
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("cwd", "expected"),
|
|
[
|
|
# Observed in this repo: bare alnum + slashes + literal dashes.
|
|
(
|
|
"/Users/h/projects/playgrounds/claude-code-sdk",
|
|
"-Users-h-projects-playgrounds-claude-code-sdk",
|
|
),
|
|
# Observed: dot-prefixed dir produces doubled dash, dash-containing
|
|
# path segments survive unchanged.
|
|
(
|
|
"/Users/h/.t3/worktrees/cars-system/t3code-9d8591ad",
|
|
"-Users-h--t3-worktrees-cars-system-t3code-9d8591ad",
|
|
),
|
|
# Trailing slash collapses to a trailing dash — claude would not
|
|
# normally see this, but the encoder is deterministic.
|
|
("/Users/h/", "-Users-h-"),
|
|
# Root.
|
|
("/", "-"),
|
|
# Spaces, parentheses, other punct all become dashes.
|
|
("/tmp/My Project (v2)", "-tmp-My-Project--v2-"),
|
|
],
|
|
)
|
|
def test_encode_known_paths(cwd: str, expected: str) -> None:
|
|
assert encode_project_key(cwd) == expected
|
|
|
|
|
|
def test_encode_rejects_relative() -> None:
|
|
with pytest.raises(ValueError, match="absolute"):
|
|
encode_project_key("relative/path")
|
|
|
|
|
|
def test_encode_rejects_empty() -> None:
|
|
with pytest.raises(ValueError, match="empty"):
|
|
encode_project_key("")
|
|
|
|
|
|
# ----- resolve_jsonl_path / session_dir --------------------------------------
|
|
|
|
|
|
def test_resolve_jsonl_path_under_fake_home(tmp_path):
|
|
sid = "deadbeef-0000-4000-8000-000000000001"
|
|
p = resolve_jsonl_path("/foo/bar", sid, home=tmp_path)
|
|
assert p == tmp_path / ".claude" / "projects" / "-foo-bar" / f"{sid}.jsonl"
|
|
|
|
|
|
def test_session_dir_matches_resolve_parent(tmp_path):
|
|
sid = "deadbeef-0000-4000-8000-000000000002"
|
|
assert resolve_jsonl_path("/a/b", sid, home=tmp_path).parent == session_dir(
|
|
"/a/b", home=tmp_path
|
|
)
|
|
|
|
|
|
def test_resolve_rejects_empty_session_id(tmp_path):
|
|
with pytest.raises(ValueError, match="session_id"):
|
|
resolve_jsonl_path("/foo", "", home=tmp_path)
|
|
|
|
|
|
def test_claude_home_and_projects_root_honor_override(tmp_path):
|
|
assert claude_home(tmp_path) == tmp_path / ".claude"
|
|
assert projects_root(tmp_path) == tmp_path / ".claude" / "projects"
|
|
|
|
|
|
# ----- find_jsonl_by_session_id ---------------------------------------------
|
|
|
|
|
|
def test_find_returns_none_when_root_missing(tmp_path):
|
|
# No `.claude/projects` under tmp_path.
|
|
assert find_jsonl_by_session_id("nope", home=tmp_path) is None
|
|
|
|
|
|
def test_find_locates_existing_session(tmp_path):
|
|
sid = "abcdef00-1111-4000-8000-000000000000"
|
|
p = resolve_jsonl_path("/some/cwd", sid, home=tmp_path)
|
|
p.parent.mkdir(parents=True)
|
|
p.write_text("{}\n")
|
|
found = find_jsonl_by_session_id(sid, home=tmp_path)
|
|
assert found == p
|
|
|
|
|
|
def test_find_rejects_empty_session_id(tmp_path):
|
|
with pytest.raises(ValueError, match="session_id"):
|
|
find_jsonl_by_session_id("", home=tmp_path)
|