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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
from __future__ import annotations
from pathlib import Path
from unittest.mock import MagicMock, patch
from pygit2 import Repository, init_repository
from pyratatui import Rect
from pygittools.tui.app import _apply_result, _persist_commit_draft, run_tui
from pygittools.tui.keys import key
from pygittools.tui.pages.home import home_page
from pygittools.tui.pages.no_repo import NoRepoPage
from pygittools.tui.types import PageAction, PageContext, PageResult
def test_persist_commit_draft_skips_without_context() -> None:
_persist_commit_draft([], None)
def test_persist_commit_draft_from_home_page(page_ctx: PageContext) -> None:
page = home_page()
page.on_enter(page_ctx)
page.changes.set_commit_message("draft")
_persist_commit_draft([page], page_ctx)
from pygittools.tui.commit_draft import load_commit_draft
assert load_commit_draft(page_ctx.repo_path, page_ctx.repo) == "draft"
def test_apply_result_replace(page_ctx: PageContext) -> None:
next_page = home_page()
stack = [NoRepoPage(Path("/tmp"))]
ctx, new_stack = _apply_result(
stack,
page_ctx,
PageResult(action=PageAction.REPLACE, next_page=next_page),
)
assert ctx is page_ctx
assert new_stack == [next_page]
def test_apply_result_replace_without_page(page_ctx: PageContext) -> None:
stack = [home_page()]
ctx, new_stack = _apply_result(stack, page_ctx, PageResult(action=PageAction.REPLACE))
assert new_stack is stack
def test_apply_result_push_and_pop(page_ctx: PageContext) -> None:
home = home_page()
home.on_enter(page_ctx)
stack = [home]
overlay = NoRepoPage(Path("/tmp"))
ctx, stack = _apply_result(stack, page_ctx, PageResult(action=PageAction.PUSH, next_page=overlay))
assert len(stack) == 2
ctx, stack = _apply_result(stack, page_ctx, PageResult(action=PageAction.POP))
assert len(stack) == 1
def test_apply_result_pop_keeps_root(page_ctx: PageContext) -> None:
home = home_page()
ctx, stack = _apply_result([home], page_ctx, PageResult(action=PageAction.POP))
assert stack == [home]
def test_apply_result_switch_repo(page_ctx: PageContext, tmp_path: Path) -> None:
repo_dir = tmp_path / "other"
repo_dir.mkdir()
init_repository(str(repo_dir), bare=False)
home = home_page()
home.on_enter(page_ctx)
ctx, stack = _apply_result(
[home],
page_ctx,
PageResult(action=PageAction.PUSH, switch_repo=repo_dir),
)
assert ctx is not None
assert stack[-1] is home
def test_apply_result_switch_repo_reenters_page(page_ctx: PageContext, tmp_path: Path) -> None:
repo_dir = tmp_path / "other"
repo_dir.mkdir()
init_repository(str(repo_dir), bare=False)
home = home_page()
home.on_enter(page_ctx)
ctx, stack = _apply_result(
[home],
page_ctx,
PageResult(action=PageAction.NONE, switch_repo=repo_dir),
)
assert ctx is not None
assert stack[-1] is home
class _FakeTerm:
def __init__(self, keys: list[object]) -> None:
self._keys = list(keys)
self.hide_cursor = MagicMock()
def __enter__(self) -> _FakeTerm:
return self
def __exit__(self, *args: object) -> bool:
return False
def draw(self, draw_fn: object) -> None:
frame = MagicMock()
frame.area = Rect(0, 0, 80, 24)
draw_fn(frame) # type: ignore[operator]
def poll_event(self, timeout_ms: int = 0) -> object | None:
del timeout_ms
if not self._keys:
return key("q")
return self._keys.pop(0)
def _run_tui_once(repo_dir: Path, keys: list[object]) -> int:
with (
patch("pygittools.tui.app.Terminal", return_value=_FakeTerm(keys)),
patch("pygittools.tui.app.init_tui_color_theme"),
patch("pygittools.tui.app.init_tab_colors"),
):
return run_tui(repo_dir)
def test_run_tui_quits_on_q(committed_repo: Repository) -> None:
assert _run_tui_once(Path(committed_repo.workdir), [key("q")]) == 0
def test_run_tui_no_repo(tmp_path: Path) -> None:
assert _run_tui_once(tmp_path, [key("q")]) == 0