1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from __future__ import annotations
from pathlib import Path
from unittest.mock import MagicMock
import pytest
from pygit2 import Repository, init_repository
from pygittools.tui.git_worktrees import (
add_worktree,
list_worktrees,
parse_worktree_porcelain,
remove_worktree,
)
def test_parse_worktree_porcelain() -> None:
text = """
worktree /repo/main
HEAD abcdef1234567890
branch refs/heads/main
worktree /repo/feature
HEAD 1111111111111111
branch refs/heads/feature
locked
worktree /repo/old
prunable gitdir file points to non-existent location
""".strip()
entries = parse_worktree_porcelain(text)
assert len(entries) == 3
assert entries[0].path == Path("/repo/main")
assert entries[0].branch == "main"
assert entries[0].head == "abcdef1234567890"
assert entries[1].locked == ""
assert entries[1].branch == "feature"
assert entries[2].prunable == "gitdir file points to non-existent location"
def test_parse_detached_and_bare() -> None:
text = """
worktree /repo/detached
HEAD deadbeef
detached
worktree /repo/bare.git
bare
""".strip()
entries = parse_worktree_porcelain(text)
assert entries[0].detached is True
assert entries[0].branch is None
assert entries[1].bare is True
def test_list_worktrees_no_workdir(monkeypatch: pytest.MonkeyPatch) -> None:
repo = MagicMock(spec=Repository)
repo.workdir = None
entries, error = list_worktrees(repo)
assert entries == []
assert error is not None
def test_add_worktree_requires_path(repo: Repository, monkeypatch: pytest.MonkeyPatch) -> None:
calls: list[list[str]] = []
def fake_run(cmd: list[str], **kwargs: object) -> MagicMock:
calls.append(cmd)
return MagicMock(returncode=0, stdout="", stderr="")
monkeypatch.setattr("pygittools.tui.git_worktrees.subprocess.run", fake_run)
ok, error = add_worktree(repo, Path("../wt"), "feature")
assert ok is True
assert error == ""
assert calls
assert "-b" in calls[0] or "feature" in calls[0]
def test_remove_worktree_force(repo: Repository, monkeypatch: pytest.MonkeyPatch) -> None:
calls: list[list[str]] = []
def fake_run(cmd: list[str], **kwargs: object) -> MagicMock:
calls.append(cmd)
return MagicMock(returncode=0, stdout="", stderr="")
monkeypatch.setattr("pygittools.tui.git_worktrees.subprocess.run", fake_run)
ok, error = remove_worktree(repo, Path("/tmp/wt"), force=True)
assert ok is True
assert "--force" in calls[0]
@pytest.fixture
def repo(tmp_path: Path) -> Repository:
repo_path = tmp_path / "repo"
repo_path.mkdir()
return init_repository(str(repo_path), bare=False)