4
4
import os
5
5
import pathlib
6
6
import textwrap
7
+ from typing import Callable
7
8
8
9
import pytest
9
10
11
+ from pytest_mock import MockerFixture
12
+
10
13
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
+ )
12
20
from libvcs .shortcuts import create_repo_from_pip_url
13
21
from libvcs .util import run , which
14
22
15
23
if not which ("git" ):
16
24
pytestmark = pytest .mark .skip (reason = "git is not available" )
17
25
18
26
27
+ RepoTestFactory = Callable [..., GitRepo ]
28
+ RepoTestFactoryLazyKwargs = Callable [..., dict ]
29
+
30
+
19
31
@pytest .fixture (autouse = True , scope = "module" )
20
32
def gitconfig (user_path : pathlib .Path ):
21
33
gitconfig = user_path / ".gitconfig"
@@ -37,7 +49,31 @@ def gitconfig_default(monkeypatch: pytest.MonkeyPatch, user_path: pathlib.Path):
37
49
monkeypatch .setenv ("HOME" , str (user_path ))
38
50
39
51
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
+ ):
41
77
"""initial commit repos return 'initial'.
42
78
43
79
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):
48
84
run (["git" , "init" , repo_name ], cwd = tmp_path )
49
85
50
86
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 ()))
58
88
59
89
git_repo .obtain ()
60
90
assert git_repo .get_revision () == "initial"
61
91
62
92
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 ()))
71
120
git_repo .obtain ()
72
121
73
122
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):
76
125
assert os .path .exists (tmp_path / "myrepo" )
77
126
78
127
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 ()))
87
156
git_repo .obtain () # clone initial repo
88
157
mocka = mocker .spy (git_repo , "run" )
89
158
git_repo .update_repo ()
@@ -98,7 +167,35 @@ def test_repo_update_handle_cases(tmp_path: pathlib.Path, git_remote, mocker):
98
167
assert mocker .call (["symbolic-ref" , "--short" , "HEAD" ]) not in mocka .mock_calls
99
168
100
169
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
+ ):
102
199
def progress_callback_spy (output , timestamp ):
103
200
assert isinstance (output , str )
104
201
assert isinstance (timestamp , datetime .datetime )
@@ -110,27 +207,43 @@ def progress_callback_spy(output, timestamp):
110
207
run (["git" , "rev-parse" , "HEAD" ], cwd = git_remote )
111
208
112
209
# 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 ()))
120
211
git_repo .obtain ()
121
212
122
213
assert progress_callback .called
123
214
124
215
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
+ ):
126
242
repo_name = "myrepo"
127
243
remote_name = "myremote"
128
244
remote_url = "https://localhost/my/git/repo.git"
129
245
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 ()))
134
247
git_repo .obtain ()
135
248
git_repo .set_remote (name = remote_name , url = remote_url )
136
249
@@ -160,17 +273,39 @@ def test_git_get_url_and_rev_from_pip_url():
160
273
assert rev == "eucalyptus"
161
274
162
275
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
+ ):
164
302
# Regression test for #14
165
303
repo_name = "myexamplegit"
166
304
repo_dir = repos_path / repo_name
167
305
remote_name = "myremote"
168
306
remote_url = "git+ssh://git@github.com/tony/AlgoXY.git"
307
+ git_repo : GitRepo = constructor (** lazy_constructor_options (** locals ()))
169
308
170
- git_repo = create_repo_from_pip_url (
171
- pip_url = f"git+file://{ git_remote } " ,
172
- repo_dir = repo_dir ,
173
- )
174
309
git_repo .obtain ()
175
310
git_repo .set_remote (name = remote_name , url = remote_url )
176
311
@@ -180,7 +315,31 @@ def test_remotes_preserves_git_ssh(repos_path, git_remote):
180
315
)
181
316
182
317
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
+ ):
184
343
pip_url_kwargs .update (
185
344
** {"pip_url" : "git+ssh://github.com:/tmp/omg/private_ssh_repo" }
186
345
)
@@ -190,14 +349,14 @@ def test_private_ssh_format(pip_url_kwargs):
190
349
excinfo .match (r"is malformatted" )
191
350
192
351
193
- def test_ls_remotes (git_repo ):
352
+ def test_ls_remotes (git_repo : GitRepo ):
194
353
remotes = git_repo .remotes ()
195
354
196
355
assert "origin" in remotes
197
356
assert "origin" in git_repo .remotes (flat = True )
198
357
199
358
200
- def test_get_remotes (git_repo ):
359
+ def test_get_remotes (git_repo : GitRepo ):
201
360
assert "origin" in git_repo .remotes ()
202
361
203
362
@@ -207,7 +366,7 @@ def test_get_remotes(git_repo):
207
366
["myrepo" , "file:///apples" ],
208
367
],
209
368
)
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 ):
211
370
mynewremote = git_repo .set_remote (name = repo_name , url = "file:///" )
212
371
213
372
assert "file:///" in mynewremote , "set_remote returns remote"
@@ -229,13 +388,13 @@ def test_set_remote(git_repo, repo_name, new_repo_url):
229
388
), "Running remove_set should overwrite previous remote"
230
389
231
390
232
- def test_get_git_version (git_repo ):
391
+ def test_get_git_version (git_repo : GitRepo ):
233
392
expected_version = git_repo .run (["--version" ]).replace ("git version " , "" )
234
393
assert git_repo .get_git_version ()
235
394
assert expected_version == git_repo .get_git_version ()
236
395
237
396
238
- def test_get_current_remote_name (git_repo ):
397
+ def test_get_current_remote_name (git_repo : GitRepo ):
239
398
assert git_repo .get_current_remote_name () == "origin"
240
399
241
400
new_branch = "another-branch-with-no-upstream"
@@ -328,7 +487,7 @@ def test_extract_status():
328
487
],
329
488
],
330
489
)
331
- def test_extract_status_b (fixture , expected_result ):
490
+ def test_extract_status_b (fixture : str , expected_result : dict ):
332
491
assert (
333
492
extract_status (textwrap .dedent (fixture ))._asdict ().items ()
334
493
>= expected_result .items ()
@@ -378,7 +537,7 @@ def test_extract_status_b(fixture, expected_result):
378
537
],
379
538
],
380
539
)
381
- def test_extract_status_c (fixture , expected_result ):
540
+ def test_extract_status_c (fixture : str , expected_result : dict ):
382
541
assert (
383
542
expected_result .items ()
384
543
<= extract_status (textwrap .dedent (fixture ))._asdict ().items ()
0 commit comments