Skip to content

Commit b11cd61

Browse files
committed
test(cli): Test sync with broken fixtures, --exit-on-error
1 parent c89e795 commit b11cd61

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

tests/test_cli.py

+138
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import pathlib
2+
import typing as t
3+
4+
import pytest
25

36
import yaml
47
from click.testing import CliRunner
58

69
from libvcs.sync.git import GitSync
710
from vcspull.cli import cli
11+
from vcspull.cli.sync import EXIT_ON_ERROR_MSG
812

913

1014
def test_sync_cli_non_existent(tmp_path: pathlib.Path) -> None:
@@ -44,3 +48,137 @@ def test_sync(
4448
assert result.exit_code == 0
4549
output = "".join(list(result.output))
4650
assert "my_git_repo" in output
51+
52+
53+
if t.TYPE_CHECKING:
54+
from typing_extensions import TypeAlias
55+
56+
ExpectedOutput: TypeAlias = t.Optional[t.Union[str, t.List[str]]]
57+
58+
59+
class SyncBrokenFixture(t.NamedTuple):
60+
test_id: str
61+
sync_args: list[str]
62+
expected_exit_code: int
63+
expected_in_output: "ExpectedOutput" = None
64+
expected_not_in_output: "ExpectedOutput" = None
65+
66+
67+
SYNC_BROKEN_REPO_FIXTURES = [
68+
SyncBrokenFixture(
69+
test_id="normal-checkout",
70+
sync_args=["my_git_repo"],
71+
expected_exit_code=0,
72+
expected_in_output="Already on 'master'",
73+
),
74+
SyncBrokenFixture(
75+
test_id="normal-checkout--exit-on-error",
76+
sync_args=["my_git_repo", "--exit-on-error"],
77+
expected_exit_code=0,
78+
expected_in_output="Already on 'master'",
79+
),
80+
SyncBrokenFixture(
81+
test_id="normal-checkout--x",
82+
sync_args=["my_git_repo", "-x"],
83+
expected_exit_code=0,
84+
expected_in_output="Already on 'master'",
85+
),
86+
SyncBrokenFixture(
87+
test_id="normal-first-broken",
88+
sync_args=["non_existent_repo", "my_git_repo"],
89+
expected_exit_code=0,
90+
expected_not_in_output=EXIT_ON_ERROR_MSG,
91+
),
92+
SyncBrokenFixture(
93+
test_id="normal-last-broken",
94+
sync_args=["my_git_repo", "non_existent_repo"],
95+
expected_exit_code=0,
96+
expected_not_in_output=EXIT_ON_ERROR_MSG,
97+
),
98+
SyncBrokenFixture(
99+
test_id="exit-on-error--exit-on-error-first-broken",
100+
sync_args=["non_existent_repo", "my_git_repo", "--exit-on-error"],
101+
expected_exit_code=1,
102+
expected_in_output=EXIT_ON_ERROR_MSG,
103+
),
104+
SyncBrokenFixture(
105+
test_id="exit-on-error--x-first-broken",
106+
sync_args=["non_existent_repo", "my_git_repo", "-x"],
107+
expected_exit_code=1,
108+
expected_in_output=EXIT_ON_ERROR_MSG,
109+
expected_not_in_output="master",
110+
),
111+
#
112+
# Verify ordering
113+
#
114+
SyncBrokenFixture(
115+
test_id="exit-on-error--exit-on-error-last-broken",
116+
sync_args=["my_git_repo", "non_existent_repo", "-x"],
117+
expected_exit_code=1,
118+
expected_in_output=[EXIT_ON_ERROR_MSG, "Already on 'master'"],
119+
),
120+
SyncBrokenFixture(
121+
test_id="exit-on-error--x-last-item",
122+
sync_args=["my_git_repo", "non_existent_repo", "--exit-on-error"],
123+
expected_exit_code=1,
124+
expected_in_output=[EXIT_ON_ERROR_MSG, "Already on 'master'"],
125+
),
126+
]
127+
128+
129+
@pytest.mark.parametrize(
130+
list(SyncBrokenFixture._fields),
131+
SYNC_BROKEN_REPO_FIXTURES,
132+
ids=[test.test_id for test in SYNC_BROKEN_REPO_FIXTURES],
133+
)
134+
def test_sync_broken(
135+
home_path: pathlib.Path,
136+
config_path: pathlib.Path,
137+
tmp_path: pathlib.Path,
138+
git_repo: GitSync,
139+
test_id: str,
140+
sync_args: list[str],
141+
expected_exit_code: int,
142+
expected_in_output: "ExpectedOutput",
143+
expected_not_in_output: "ExpectedOutput",
144+
) -> None:
145+
runner = CliRunner()
146+
147+
github_projects = home_path / "github_projects"
148+
my_git_repo = github_projects / "my_git_repo"
149+
if my_git_repo.is_dir():
150+
my_git_repo.rmdir()
151+
152+
with runner.isolated_filesystem(temp_dir=tmp_path):
153+
config = {
154+
"~/github_projects/": {
155+
"my_git_repo": {
156+
"url": f"git+file://{git_repo.dir}",
157+
"remotes": {"test_remote": f"git+file://{git_repo.dir}"},
158+
},
159+
"non_existent_repo": {
160+
"url": "git+file:///dev/null",
161+
},
162+
}
163+
}
164+
yaml_config = config_path / ".vcspull.yaml"
165+
yaml_config_data = yaml.dump(config, default_flow_style=False)
166+
yaml_config.write_text(yaml_config_data, encoding="utf-8")
167+
168+
# CLI can sync
169+
assert isinstance(sync_args, list)
170+
result = runner.invoke(cli, ["sync", *sync_args])
171+
assert result.exit_code == expected_exit_code
172+
output = "".join(list(result.output))
173+
174+
if expected_in_output is not None:
175+
if isinstance(expected_in_output, str):
176+
expected_in_output = [expected_in_output]
177+
for needle in expected_in_output:
178+
assert needle in output
179+
180+
if expected_not_in_output is not None:
181+
if isinstance(expected_not_in_output, str):
182+
expected_not_in_output = [expected_not_in_output]
183+
for needle in expected_not_in_output:
184+
assert needle not in output

0 commit comments

Comments
 (0)