Skip to content

Commit fce9809

Browse files
authored
tests(git): Remotes, Part 1 (refactors, annotations, #309)
In re: vcs-python/vcspull#362
2 parents c551efc + 5fe95a7 commit fce9809

File tree

1 file changed

+210
-51
lines changed

1 file changed

+210
-51
lines changed

tests/test_git.py

Lines changed: 210 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,30 @@
44
import os
55
import pathlib
66
import textwrap
7+
from typing import Callable
78

89
import pytest
910

11+
from pytest_mock import MockerFixture
12+
1013
from libvcs import exc
11-
from libvcs.git import GitRemote, convert_pip_url as git_convert_pip_url, extract_status
14+
from libvcs.git import (
15+
GitRemote,
16+
GitRepo,
17+
convert_pip_url as git_convert_pip_url,
18+
extract_status,
19+
)
1220
from libvcs.shortcuts import create_repo_from_pip_url
1321
from libvcs.util import run, which
1422

1523
if not which("git"):
1624
pytestmark = pytest.mark.skip(reason="git is not available")
1725

1826

27+
RepoTestFactory = Callable[..., GitRepo]
28+
RepoTestFactoryLazyKwargs = Callable[..., dict]
29+
30+
1931
@pytest.fixture(autouse=True, scope="module")
2032
def gitconfig(user_path: pathlib.Path):
2133
gitconfig = user_path / ".gitconfig"
@@ -37,7 +49,31 @@ def gitconfig_default(monkeypatch: pytest.MonkeyPatch, user_path: pathlib.Path):
3749
monkeypatch.setenv("HOME", str(user_path))
3850

3951

40-
def test_repo_git_obtain_initial_commit_repo(tmp_path: pathlib.Path):
52+
@pytest.mark.parametrize(
53+
# Postpone evaluation of options so fixture variables can interpolate
54+
"constructor,lazy_constructor_options",
55+
[
56+
[
57+
GitRepo,
58+
lambda bare_repo_dir, tmp_path, **kwargs: {
59+
"url": f"file://{bare_repo_dir}",
60+
"repo_dir": tmp_path / "obtaining a bare repo",
61+
},
62+
],
63+
[
64+
create_repo_from_pip_url,
65+
lambda bare_repo_dir, tmp_path, **kwargs: {
66+
"pip_url": f"git+file://{bare_repo_dir}",
67+
"repo_dir": tmp_path / "obtaining a bare repo",
68+
},
69+
],
70+
],
71+
)
72+
def test_repo_git_obtain_initial_commit_repo(
73+
tmp_path: pathlib.Path,
74+
constructor: RepoTestFactory,
75+
lazy_constructor_options: RepoTestFactoryLazyKwargs,
76+
):
4177
"""initial commit repos return 'initial'.
4278
4379
note: this behaviors differently from git(1)'s use of the word "bare".
@@ -48,26 +84,39 @@ def test_repo_git_obtain_initial_commit_repo(tmp_path: pathlib.Path):
4884
run(["git", "init", repo_name], cwd=tmp_path)
4985

5086
bare_repo_dir = tmp_path / repo_name
51-
52-
git_repo = create_repo_from_pip_url(
53-
**{
54-
"pip_url": f"git+file://{bare_repo_dir}",
55-
"repo_dir": tmp_path / "obtaining a bare repo",
56-
}
57-
)
87+
git_repo: GitRepo = constructor(**lazy_constructor_options(**locals()))
5888

5989
git_repo.obtain()
6090
assert git_repo.get_revision() == "initial"
6191

6292

63-
def test_repo_git_obtain_full(tmp_path: pathlib.Path, git_remote):
64-
git_repo = create_repo_from_pip_url(
65-
**{
66-
"pip_url": f"git+file://{git_remote}",
67-
"repo_dir": tmp_path / "myrepo",
68-
}
69-
)
70-
93+
@pytest.mark.parametrize(
94+
# Postpone evaluation of options so fixture variables can interpolate
95+
"constructor,lazy_constructor_options",
96+
[
97+
[
98+
GitRepo,
99+
lambda git_remote, tmp_path, **kwargs: {
100+
"url": f"file://{git_remote}",
101+
"repo_dir": tmp_path / "myrepo",
102+
},
103+
],
104+
[
105+
create_repo_from_pip_url,
106+
lambda git_remote, tmp_path, **kwargs: {
107+
"pip_url": f"git+file://{git_remote}",
108+
"repo_dir": tmp_path / "myrepo",
109+
},
110+
],
111+
],
112+
)
113+
def test_repo_git_obtain_full(
114+
tmp_path: pathlib.Path,
115+
git_remote,
116+
constructor: RepoTestFactory,
117+
lazy_constructor_options: RepoTestFactoryLazyKwargs,
118+
):
119+
git_repo: GitRepo = constructor(**lazy_constructor_options(**locals()))
71120
git_repo.obtain()
72121

73122
test_repo_revision = run(["git", "rev-parse", "HEAD"], cwd=git_remote)
@@ -76,14 +125,34 @@ def test_repo_git_obtain_full(tmp_path: pathlib.Path, git_remote):
76125
assert os.path.exists(tmp_path / "myrepo")
77126

78127

79-
def test_repo_update_handle_cases(tmp_path: pathlib.Path, git_remote, mocker):
80-
git_repo = create_repo_from_pip_url(
81-
**{
82-
"pip_url": f"git+file://{git_remote}",
83-
"repo_dir": tmp_path / "myrepo",
84-
}
85-
)
86-
128+
@pytest.mark.parametrize(
129+
# Postpone evaluation of options so fixture variables can interpolate
130+
"constructor,lazy_constructor_options",
131+
[
132+
[
133+
GitRepo,
134+
lambda git_remote, tmp_path, **kwargs: {
135+
"url": f"file://{git_remote}",
136+
"repo_dir": tmp_path / "myrepo",
137+
},
138+
],
139+
[
140+
create_repo_from_pip_url,
141+
lambda git_remote, tmp_path, **kwargs: {
142+
"pip_url": f"git+file://{git_remote}",
143+
"repo_dir": tmp_path / "myrepo",
144+
},
145+
],
146+
],
147+
)
148+
def test_repo_update_handle_cases(
149+
tmp_path: pathlib.Path,
150+
git_remote: pathlib.Path,
151+
mocker: MockerFixture,
152+
constructor: RepoTestFactory,
153+
lazy_constructor_options: RepoTestFactoryLazyKwargs,
154+
):
155+
git_repo: GitRepo = constructor(**lazy_constructor_options(**locals()))
87156
git_repo.obtain() # clone initial repo
88157
mocka = mocker.spy(git_repo, "run")
89158
git_repo.update_repo()
@@ -98,7 +167,35 @@ def test_repo_update_handle_cases(tmp_path: pathlib.Path, git_remote, mocker):
98167
assert mocker.call(["symbolic-ref", "--short", "HEAD"]) not in mocka.mock_calls
99168

100169

101-
def test_progress_callback(tmp_path: pathlib.Path, git_remote, mocker):
170+
@pytest.mark.parametrize(
171+
# Postpone evaluation of options so fixture variables can interpolate
172+
"constructor,lazy_constructor_options",
173+
[
174+
[
175+
GitRepo,
176+
lambda git_remote, tmp_path, progress_callback, **kwargs: {
177+
"url": f"file://{git_remote}",
178+
"repo_dir": tmp_path / "myrepo",
179+
"progress_callback": progress_callback,
180+
},
181+
],
182+
[
183+
create_repo_from_pip_url,
184+
lambda git_remote, tmp_path, progress_callback, **kwargs: {
185+
"pip_url": f"git+file://{git_remote}",
186+
"repo_dir": tmp_path / "myrepo",
187+
"progress_callback": progress_callback,
188+
},
189+
],
190+
],
191+
)
192+
def test_progress_callback(
193+
tmp_path: pathlib.Path,
194+
git_remote: pathlib.Path,
195+
mocker: MockerFixture,
196+
constructor: RepoTestFactory,
197+
lazy_constructor_options: RepoTestFactoryLazyKwargs,
198+
):
102199
def progress_callback_spy(output, timestamp):
103200
assert isinstance(output, str)
104201
assert isinstance(timestamp, datetime.datetime)
@@ -110,27 +207,43 @@ def progress_callback_spy(output, timestamp):
110207
run(["git", "rev-parse", "HEAD"], cwd=git_remote)
111208

112209
# create a new repo with the repo as a remote
113-
git_repo = create_repo_from_pip_url(
114-
**{
115-
"pip_url": f"git+file://{git_remote}",
116-
"repo_dir": tmp_path / "myrepo",
117-
"progress_callback": progress_callback,
118-
}
119-
)
210+
git_repo: GitRepo = constructor(**lazy_constructor_options(**locals()))
120211
git_repo.obtain()
121212

122213
assert progress_callback.called
123214

124215

125-
def test_remotes(repos_path, git_remote):
216+
@pytest.mark.parametrize(
217+
# Postpone evaluation of options so fixture variables can interpolate
218+
"constructor,lazy_constructor_options",
219+
[
220+
[
221+
GitRepo,
222+
lambda git_remote, repos_path, repo_name, **kwargs: {
223+
"url": f"file://{git_remote}",
224+
"repo_dir": repos_path / repo_name,
225+
},
226+
],
227+
[
228+
create_repo_from_pip_url,
229+
lambda git_remote, repos_path, repo_name, **kwargs: {
230+
"pip_url": f"git+file://{git_remote}",
231+
"repo_dir": repos_path / repo_name,
232+
},
233+
],
234+
],
235+
)
236+
def test_remotes(
237+
repos_path: pathlib.Path,
238+
git_remote: pathlib.Path,
239+
constructor: RepoTestFactory,
240+
lazy_constructor_options: RepoTestFactoryLazyKwargs,
241+
):
126242
repo_name = "myrepo"
127243
remote_name = "myremote"
128244
remote_url = "https://localhost/my/git/repo.git"
129245

130-
git_repo = create_repo_from_pip_url(
131-
pip_url=f"git+file://{git_remote}",
132-
repo_dir=repos_path / repo_name,
133-
)
246+
git_repo: GitRepo = constructor(**lazy_constructor_options(**locals()))
134247
git_repo.obtain()
135248
git_repo.set_remote(name=remote_name, url=remote_url)
136249

@@ -160,17 +273,39 @@ def test_git_get_url_and_rev_from_pip_url():
160273
assert rev == "eucalyptus"
161274

162275

163-
def test_remotes_preserves_git_ssh(repos_path, git_remote):
276+
@pytest.mark.parametrize(
277+
# Postpone evaluation of options so fixture variables can interpolate
278+
"constructor,lazy_constructor_options",
279+
[
280+
[
281+
GitRepo,
282+
lambda git_remote, repo_dir, **kwargs: {
283+
"url": f"file://{git_remote}",
284+
"repo_dir": str(repo_dir),
285+
},
286+
],
287+
[
288+
create_repo_from_pip_url,
289+
lambda git_remote, repo_dir, **kwargs: {
290+
"pip_url": f"git+file://{git_remote}",
291+
"repo_dir": repo_dir,
292+
},
293+
],
294+
],
295+
)
296+
def test_remotes_preserves_git_ssh(
297+
repos_path: pathlib.Path,
298+
git_remote: pathlib.Path,
299+
constructor: RepoTestFactory,
300+
lazy_constructor_options: RepoTestFactoryLazyKwargs,
301+
):
164302
# Regression test for #14
165303
repo_name = "myexamplegit"
166304
repo_dir = repos_path / repo_name
167305
remote_name = "myremote"
168306
remote_url = "git+ssh://git@github.com/tony/AlgoXY.git"
307+
git_repo: GitRepo = constructor(**lazy_constructor_options(**locals()))
169308

170-
git_repo = create_repo_from_pip_url(
171-
pip_url=f"git+file://{git_remote}",
172-
repo_dir=repo_dir,
173-
)
174309
git_repo.obtain()
175310
git_repo.set_remote(name=remote_name, url=remote_url)
176311

@@ -180,7 +315,31 @@ def test_remotes_preserves_git_ssh(repos_path, git_remote):
180315
)
181316

182317

183-
def test_private_ssh_format(pip_url_kwargs):
318+
@pytest.mark.parametrize(
319+
# Postpone evaluation of options so fixture variables can interpolate
320+
"constructor,lazy_constructor_options",
321+
[
322+
[
323+
GitRepo,
324+
lambda bare_repo_dir, tmp_path, **kwargs: {
325+
"url": f"file://{bare_repo_dir}",
326+
"repo_dir": tmp_path / "obtaining a bare repo",
327+
},
328+
],
329+
[
330+
create_repo_from_pip_url,
331+
lambda bare_repo_dir, tmp_path, **kwargs: {
332+
"pip_url": f"git+file://{bare_repo_dir}",
333+
"repo_dir": tmp_path / "obtaining a bare repo",
334+
},
335+
],
336+
],
337+
)
338+
def test_private_ssh_format(
339+
pip_url_kwargs: dict,
340+
constructor: RepoTestFactory,
341+
lazy_constructor_options: RepoTestFactoryLazyKwargs,
342+
):
184343
pip_url_kwargs.update(
185344
**{"pip_url": "git+ssh://github.com:/tmp/omg/private_ssh_repo"}
186345
)
@@ -190,14 +349,14 @@ def test_private_ssh_format(pip_url_kwargs):
190349
excinfo.match(r"is malformatted")
191350

192351

193-
def test_ls_remotes(git_repo):
352+
def test_ls_remotes(git_repo: GitRepo):
194353
remotes = git_repo.remotes()
195354

196355
assert "origin" in remotes
197356
assert "origin" in git_repo.remotes(flat=True)
198357

199358

200-
def test_get_remotes(git_repo):
359+
def test_get_remotes(git_repo: GitRepo):
201360
assert "origin" in git_repo.remotes()
202361

203362

@@ -207,7 +366,7 @@ def test_get_remotes(git_repo):
207366
["myrepo", "file:///apples"],
208367
],
209368
)
210-
def test_set_remote(git_repo, repo_name, new_repo_url):
369+
def test_set_remote(git_repo: GitRepo, repo_name: str, new_repo_url: str):
211370
mynewremote = git_repo.set_remote(name=repo_name, url="file:///")
212371

213372
assert "file:///" in mynewremote, "set_remote returns remote"
@@ -229,13 +388,13 @@ def test_set_remote(git_repo, repo_name, new_repo_url):
229388
), "Running remove_set should overwrite previous remote"
230389

231390

232-
def test_get_git_version(git_repo):
391+
def test_get_git_version(git_repo: GitRepo):
233392
expected_version = git_repo.run(["--version"]).replace("git version ", "")
234393
assert git_repo.get_git_version()
235394
assert expected_version == git_repo.get_git_version()
236395

237396

238-
def test_get_current_remote_name(git_repo):
397+
def test_get_current_remote_name(git_repo: GitRepo):
239398
assert git_repo.get_current_remote_name() == "origin"
240399

241400
new_branch = "another-branch-with-no-upstream"
@@ -328,7 +487,7 @@ def test_extract_status():
328487
],
329488
],
330489
)
331-
def test_extract_status_b(fixture, expected_result):
490+
def test_extract_status_b(fixture: str, expected_result: dict):
332491
assert (
333492
extract_status(textwrap.dedent(fixture))._asdict().items()
334493
>= expected_result.items()
@@ -378,7 +537,7 @@ def test_extract_status_b(fixture, expected_result):
378537
],
379538
],
380539
)
381-
def test_extract_status_c(fixture, expected_result):
540+
def test_extract_status_c(fixture: str, expected_result: dict):
382541
assert (
383542
expected_result.items()
384543
<= extract_status(textwrap.dedent(fixture))._asdict().items()

0 commit comments

Comments
 (0)