Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 43cac24

Browse filesBrowse files
committed
tests(test[pytest_plugin]): Add comprehensive tests for Git init compatibility
why: Ensure Git init compatibility fix works across all scenarios what: - Test basic and bare repository creation - Test Git version compatibility with mocked old/new Git - Test configuration hierarchy (param > env > default) - Test error handling for permission errors - Test post-init callback execution - Add integration test with real Git command Tests use monkeypatch to simulate different Git versions and ensure the fallback mechanism works correctly for older Git versions that don't support --initial-branch.
1 parent ab06a56 commit 43cac24
Copy full SHA for 43cac24

File tree

Expand file treeCollapse file tree

1 file changed

+223
-0
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+223
-0
lines changed

‎tests/test_pytest_plugin.py

Copy file name to clipboardExpand all lines: tests/test_pytest_plugin.py
+223Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
import pytest
1010

1111
from libvcs._internal.run import run
12+
from libvcs.cmd.git import Git
13+
from libvcs.exc import CommandError
14+
from libvcs.pytest_plugin import (
15+
DEFAULT_GIT_INITIAL_BRANCH,
16+
_create_git_remote_repo,
17+
)
1218

1319
if t.TYPE_CHECKING:
1420
import pathlib
@@ -176,3 +182,220 @@ def test_git_bare_repo_sync_and_commit(
176182
# Test
177183
result = pytester.runpytest(str(first_test_filename))
178184
result.assert_outcomes(passed=2)
185+
186+
187+
def test_create_git_remote_repo_basic(tmp_path: pathlib.Path) -> None:
188+
"""Test basic git repository creation."""
189+
repo_path = tmp_path / "test-repo"
190+
191+
result = _create_git_remote_repo(repo_path, init_cmd_args=[])
192+
193+
assert result == repo_path
194+
assert repo_path.exists()
195+
assert (repo_path / ".git").exists()
196+
197+
198+
def test_create_git_remote_repo_bare(tmp_path: pathlib.Path) -> None:
199+
"""Test bare git repository creation."""
200+
repo_path = tmp_path / "test-repo.git"
201+
202+
result = _create_git_remote_repo(repo_path, init_cmd_args=["--bare"])
203+
204+
assert result == repo_path
205+
assert repo_path.exists()
206+
assert (repo_path / "HEAD").exists()
207+
assert not (repo_path / ".git").exists()
208+
209+
210+
def test_create_git_remote_repo_with_initial_branch(
211+
tmp_path: pathlib.Path,
212+
monkeypatch: pytest.MonkeyPatch,
213+
) -> None:
214+
"""Test repository creation with custom initial branch.
215+
216+
This test checks both modern Git (2.30.0+) and fallback behavior.
217+
"""
218+
repo_path = tmp_path / "test-repo"
219+
220+
# Track Git.init calls
221+
init_calls: list[dict[str, t.Any]] = []
222+
223+
def mock_init(self: Git, *args: t.Any, **kwargs: t.Any) -> str:
224+
init_calls.append({"args": args, "kwargs": kwargs})
225+
226+
# Simulate old Git that doesn't support --initial-branch
227+
if kwargs.get("initial_branch"):
228+
msg = "error: unknown option `initial-branch'"
229+
raise CommandError(
230+
msg,
231+
returncode=1,
232+
cmd=["git", "init", "--initial-branch=main"],
233+
)
234+
235+
# Create the repo directory to simulate successful init
236+
self.path.mkdir(exist_ok=True)
237+
(self.path / ".git").mkdir(exist_ok=True)
238+
return "Initialized empty Git repository"
239+
240+
monkeypatch.setattr(Git, "init", mock_init)
241+
242+
result = _create_git_remote_repo(repo_path, initial_branch="develop")
243+
244+
# Should have tried twice: once with initial_branch, once without
245+
assert len(init_calls) == 2
246+
assert init_calls[0]["kwargs"].get("initial_branch") == "develop"
247+
assert "initial_branch" not in init_calls[1]["kwargs"]
248+
assert result == repo_path
249+
250+
251+
def test_create_git_remote_repo_modern_git(
252+
tmp_path: pathlib.Path,
253+
monkeypatch: pytest.MonkeyPatch,
254+
) -> None:
255+
"""Test repository creation with Git 2.30.0+ that supports --initial-branch."""
256+
repo_path = tmp_path / "test-repo"
257+
258+
init_calls: list[dict[str, t.Any]] = []
259+
260+
def mock_init(self: Git, *args: t.Any, **kwargs: t.Any) -> str:
261+
init_calls.append({"args": args, "kwargs": kwargs})
262+
# Simulate successful init with --initial-branch support
263+
self.path.mkdir(exist_ok=True)
264+
(self.path / ".git").mkdir(exist_ok=True)
265+
branch = kwargs.get("initial_branch", "master")
266+
return f"Initialized empty Git repository with initial branch '{branch}'"
267+
268+
monkeypatch.setattr(Git, "init", mock_init)
269+
270+
result = _create_git_remote_repo(repo_path, initial_branch="main")
271+
272+
# Should only call init once since it succeeded
273+
assert len(init_calls) == 1
274+
assert init_calls[0]["kwargs"].get("initial_branch") == "main"
275+
assert result == repo_path
276+
277+
278+
@pytest.mark.parametrize(
279+
("env_var", "param", "expected_branch"),
280+
[
281+
("custom-env", None, "custom-env"), # Use env var
282+
("custom-env", "param-override", "param-override"), # Param overrides env
283+
(None, "explicit-param", "explicit-param"), # Use param
284+
(None, None, DEFAULT_GIT_INITIAL_BRANCH), # Use default
285+
],
286+
)
287+
def test_create_git_remote_repo_branch_configuration(
288+
tmp_path: pathlib.Path,
289+
monkeypatch: pytest.MonkeyPatch,
290+
env_var: str | None,
291+
param: str | None,
292+
expected_branch: str,
293+
) -> None:
294+
"""Test initial branch configuration hierarchy."""
295+
# Always reload the module to ensure fresh state
296+
import sys
297+
298+
if "libvcs.pytest_plugin" in sys.modules:
299+
del sys.modules["libvcs.pytest_plugin"]
300+
301+
if env_var:
302+
monkeypatch.setenv("LIBVCS_GIT_DEFAULT_INITIAL_BRANCH", env_var)
303+
304+
# Import after setting env var
305+
from libvcs.pytest_plugin import _create_git_remote_repo
306+
307+
repo_path = tmp_path / "test-repo"
308+
309+
# Track what branch was used
310+
used_branch = None
311+
312+
def mock_init(self: Git, *args: t.Any, **kwargs: t.Any) -> str:
313+
nonlocal used_branch
314+
used_branch = kwargs.get("initial_branch")
315+
self.path.mkdir(exist_ok=True)
316+
(self.path / ".git").mkdir(exist_ok=True)
317+
return "Initialized"
318+
319+
monkeypatch.setattr(Git, "init", mock_init)
320+
321+
_create_git_remote_repo(repo_path, initial_branch=param)
322+
323+
assert used_branch == expected_branch
324+
325+
326+
def test_create_git_remote_repo_post_init_callback(tmp_path: pathlib.Path) -> None:
327+
"""Test that post-init callback is executed."""
328+
repo_path = tmp_path / "test-repo"
329+
callback_executed = False
330+
callback_path = None
331+
332+
def post_init_callback(
333+
remote_repo_path: pathlib.Path, env: t.Any = None
334+
) -> None:
335+
nonlocal callback_executed, callback_path
336+
callback_executed = True
337+
callback_path = remote_repo_path
338+
(remote_repo_path / "callback-marker.txt").write_text("executed")
339+
340+
_create_git_remote_repo(
341+
repo_path,
342+
remote_repo_post_init=post_init_callback,
343+
init_cmd_args=[], # Create non-bare repo for easier testing
344+
)
345+
346+
assert callback_executed
347+
assert callback_path == repo_path
348+
assert (repo_path / "callback-marker.txt").exists()
349+
assert (repo_path / "callback-marker.txt").read_text() == "executed"
350+
351+
352+
def test_create_git_remote_repo_permission_error(
353+
tmp_path: pathlib.Path,
354+
monkeypatch: pytest.MonkeyPatch,
355+
) -> None:
356+
"""Test handling of permission errors."""
357+
repo_path = tmp_path / "test-repo"
358+
359+
def mock_init(self: Git, *args: t.Any, **kwargs: t.Any) -> str:
360+
msg = "fatal: cannot mkdir .git: Permission denied"
361+
raise CommandError(
362+
msg,
363+
returncode=128,
364+
cmd=["git", "init"],
365+
)
366+
367+
monkeypatch.setattr(Git, "init", mock_init)
368+
369+
with pytest.raises(CommandError) as exc_info:
370+
_create_git_remote_repo(repo_path)
371+
372+
assert "Permission denied" in str(exc_info.value)
373+
374+
375+
@pytest.mark.skipif(
376+
not shutil.which("git"),
377+
reason="git is not available",
378+
)
379+
def test_create_git_remote_repo_integration(tmp_path: pathlib.Path) -> None:
380+
"""Integration test with real git command."""
381+
repo_path = tmp_path / "integration-repo"
382+
383+
result = _create_git_remote_repo(repo_path, initial_branch="development")
384+
385+
assert result == repo_path
386+
assert repo_path.exists()
387+
388+
# Check actual git status
389+
git = Git(path=repo_path)
390+
391+
# Get git version to determine what to check
392+
try:
393+
version = git.version()
394+
if version.major > 2 or (version.major == 2 and version.minor >= 30):
395+
# Can check branch name on modern Git
396+
branch_output = git.run(["symbolic-ref", "HEAD"])
397+
assert "refs/heads/development" in branch_output
398+
except Exception:
399+
# Just verify it's a valid repo
400+
status = git.run(["status", "--porcelain"])
401+
assert isinstance(status, str)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.