Files
NCBM 5b4d3985b7 core/tools/vcs: add read-only vcs_* agent tools
Expose vcs_kind/status/diff/log/branch over detect_vcs; cover git and
custom detector registration.
2026-07-15 10:22:00 +08:00

111 lines
3.0 KiB
Python

from __future__ import annotations
import shutil
import subprocess
from pathlib import Path
from typing import TYPE_CHECKING
import pytest
from plyngent.tools.vcs import (
detect_vcs,
vcs_branch,
vcs_diff,
vcs_kind,
vcs_log,
vcs_status,
)
from plyngent.tools.vcs.detect import clear_extra_detectors, register_detector
from tests.test_tools.helpers import call_sync
if TYPE_CHECKING:
from plyngent.tools.vcs.backend import VcsBackend
pytestmark = pytest.mark.skipif(shutil.which("git") is None, reason="git not installed")
def _git(root: Path, *args: str) -> None:
completed = subprocess.run(
["git", *args],
cwd=root,
check=True,
capture_output=True,
text=True,
)
del completed
def _init_repo(root: Path) -> None:
_git(root, "init")
_git(root, "config", "user.email", "test@example.com")
_git(root, "config", "user.name", "Test")
_ = (root / "readme.txt").write_text("hello\n", encoding="utf-8")
_git(root, "add", "readme.txt")
_git(root, "commit", "-m", "initial")
def test_detect_none(workspace: object) -> None:
assert isinstance(workspace, Path)
assert detect_vcs(workspace) is None
assert "no supported VCS" in call_sync(vcs_status)
def test_git_status_and_kind(workspace: object) -> None:
assert isinstance(workspace, Path)
_init_repo(workspace)
assert call_sync(vcs_kind) == "git"
status = call_sync(vcs_status)
assert "readme" in status or "main" in status or "master" in status or status == "(clean)"
def test_git_log_and_branch(workspace: object) -> None:
assert isinstance(workspace, Path)
_init_repo(workspace)
log = call_sync(vcs_log, limit=5)
assert "initial" in log
branch = call_sync(vcs_branch)
assert branch # main/master/detached — non-empty
def test_git_diff(workspace: object) -> None:
assert isinstance(workspace, Path)
_init_repo(workspace)
_ = (workspace / "readme.txt").write_text("hello\nworld\n", encoding="utf-8")
diff = call_sync(vcs_diff)
assert "world" in diff or "readme" in diff
def test_register_custom_detector(workspace: object) -> None:
assert isinstance(workspace, Path)
class FakeBackend:
@property
def kind(self) -> str:
return "fake"
def status(self) -> str:
return "fake-status"
def diff(self, *, staged: bool = False, path: str | None = None) -> str:
del staged, path
return "fake-diff"
def log(self, *, limit: int = 10) -> str:
del limit
return "fake-log"
def branch(self) -> str:
return "fake-branch"
def detect_fake(root: Path) -> VcsBackend | None:
del root
return FakeBackend()
register_detector(detect_fake, prepend=True)
try:
assert call_sync(vcs_kind) == "fake"
assert call_sync(vcs_status) == "fake-status"
assert call_sync(vcs_branch) == "fake-branch"
finally:
clear_extra_detectors()