b4fbd6fe9f
Deploy Site / deploy-vercel (push) Has been skipped
Deploy Site / deploy-docs (push) Has been skipped
Build Skills Index / build-index (push) Has been skipped
CI / Deny unrelated histories (push) Has been skipped
CI / Detect affected areas (push) Successful in 27m35s
CI / OSV scan (push) Failing after 4s
CI / Build&Test Docker image (push) Successful in 9s
CI / Supply-chain scan (push) Has been skipped
CI / Lint Docker scripts (push) Failing after 5m13s
CI / Check contributors (push) Failing after 12m8s
CI / Docs Site (push) Failing after 12m8s
CI / TypeScript (push) Failing after 12m8s
CI / Python lints (push) Failing after 12m9s
CI / Python tests (push) Failing after 12m9s
CI / Check uv.lock (push) Failing after 23m22s
CI / CI timing report (push) Has been cancelled
Build Skills Index / trigger-deploy (push) Has been cancelled
CI / All required checks pass (push) Has been cancelled
140 lines
3.8 KiB
Python
140 lines
3.8 KiB
Python
"""Tests for workspace + project-root resolution."""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from agent.lsp.workspace import (
|
|
clear_cache,
|
|
find_git_worktree,
|
|
is_inside_workspace,
|
|
nearest_root,
|
|
normalize_path,
|
|
resolve_workspace_for_file,
|
|
)
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _clear():
|
|
clear_cache()
|
|
yield
|
|
clear_cache()
|
|
|
|
|
|
def test_find_git_worktree_returns_none_outside_repo(tmp_path: Path):
|
|
sub = tmp_path / "sub"
|
|
sub.mkdir()
|
|
assert find_git_worktree(str(sub)) is None
|
|
|
|
|
|
def test_find_git_worktree_finds_dotgit(tmp_path: Path):
|
|
repo = tmp_path / "repo"
|
|
repo.mkdir()
|
|
(repo / ".git").mkdir()
|
|
sub = repo / "src" / "deep"
|
|
sub.mkdir(parents=True)
|
|
assert find_git_worktree(str(sub)) == str(repo)
|
|
|
|
|
|
def test_find_git_worktree_handles_dotgit_file(tmp_path: Path):
|
|
"""``.git`` can also be a file (gitfile pointing into a worktree)."""
|
|
repo = tmp_path / "repo"
|
|
repo.mkdir()
|
|
(repo / ".git").write_text("gitdir: /elsewhere\n")
|
|
assert find_git_worktree(str(repo)) == str(repo)
|
|
|
|
|
|
def test_is_inside_workspace_true_for_subpath(tmp_path: Path):
|
|
root = tmp_path / "p"
|
|
root.mkdir()
|
|
sub = root / "x" / "y.py"
|
|
sub.parent.mkdir(parents=True)
|
|
sub.write_text("")
|
|
assert is_inside_workspace(str(sub), str(root))
|
|
|
|
|
|
def test_is_inside_workspace_false_for_unrelated(tmp_path: Path):
|
|
a = tmp_path / "a"
|
|
b = tmp_path / "b"
|
|
a.mkdir()
|
|
b.mkdir()
|
|
f = b / "x.py"
|
|
f.write_text("")
|
|
assert not is_inside_workspace(str(f), str(a))
|
|
|
|
|
|
def test_nearest_root_finds_first_marker(tmp_path: Path):
|
|
root = tmp_path / "p"
|
|
deep = root / "src" / "pkg"
|
|
deep.mkdir(parents=True)
|
|
(root / "pyproject.toml").write_text("")
|
|
found = nearest_root(str(deep / "mod.py"), ["pyproject.toml"])
|
|
assert found == str(root)
|
|
|
|
|
|
def test_nearest_root_excludes_take_priority(tmp_path: Path):
|
|
"""If an exclude marker matches first, return None."""
|
|
root = tmp_path / "p"
|
|
sub = root / "deno-app"
|
|
sub.mkdir(parents=True)
|
|
(sub / "deno.json").write_text("{}")
|
|
(root / "package.json").write_text("{}") # would match if not for exclude
|
|
found = nearest_root(
|
|
str(sub / "main.ts"),
|
|
["package.json"],
|
|
excludes=["deno.json"],
|
|
)
|
|
assert found is None
|
|
|
|
|
|
def test_nearest_root_returns_none_when_no_marker(tmp_path: Path):
|
|
f = tmp_path / "x.py"
|
|
f.write_text("")
|
|
assert nearest_root(str(f), ["pyproject.toml"]) is None
|
|
|
|
|
|
def test_resolve_workspace_for_file_uses_cwd_first(tmp_path: Path, monkeypatch):
|
|
repo = tmp_path / "repo"
|
|
(repo / ".git").mkdir(parents=True)
|
|
file_path = repo / "x.py"
|
|
file_path.write_text("")
|
|
# cwd is inside the repo
|
|
monkeypatch.chdir(str(repo))
|
|
root, gated = resolve_workspace_for_file(str(file_path))
|
|
assert root == str(repo)
|
|
assert gated is True
|
|
|
|
|
|
def test_resolve_workspace_for_file_no_repo_returns_none(tmp_path: Path, monkeypatch):
|
|
monkeypatch.chdir(str(tmp_path))
|
|
f = tmp_path / "x.py"
|
|
f.write_text("")
|
|
root, gated = resolve_workspace_for_file(str(f))
|
|
assert root is None
|
|
assert gated is False
|
|
|
|
|
|
def test_resolve_workspace_falls_back_to_file_location(tmp_path: Path, monkeypatch):
|
|
"""When cwd isn't a git repo but the file is inside one, we still
|
|
discover the workspace from the file's path."""
|
|
not_a_repo = tmp_path / "loose"
|
|
not_a_repo.mkdir()
|
|
monkeypatch.chdir(str(not_a_repo))
|
|
|
|
repo = tmp_path / "actual-repo"
|
|
(repo / ".git").mkdir(parents=True)
|
|
f = repo / "x.py"
|
|
f.write_text("")
|
|
|
|
root, gated = resolve_workspace_for_file(str(f))
|
|
assert root == str(repo)
|
|
assert gated is True
|
|
|
|
|
|
def test_normalize_path_expands_tilde(monkeypatch):
|
|
monkeypatch.setenv("HOME", "/home/user")
|
|
p = normalize_path("~/x.py")
|
|
assert p == os.path.abspath("/home/user/x.py")
|