Skip to content

Commit 9fa395f

Browse files
committed
tests/cmd(test[GitBranch]): add tests for branch operations
why: Verify GitBranchCmd methods work correctly what: - Add test_branch_delete with NamedTuple parametrization - Add test_branch_rename with NamedTuple parametrization - Add test_branch_copy with NamedTuple parametrization - Add test_branch_set_upstream with NamedTuple parametrization - Add test_branch_unset_upstream - Use test_id pattern for all fixtures
1 parent 537fa86 commit 9fa395f

1 file changed

Lines changed: 229 additions & 0 deletions

File tree

tests/cmd/test_git.py

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77

88
import pytest
99

10+
from libvcs._internal.query_list import ObjectDoesNotExist
1011
from libvcs.cmd import git
1112

13+
if t.TYPE_CHECKING:
14+
from libvcs.sync.git import GitSync
15+
1216

1317
@pytest.mark.parametrize("path_type", [str, pathlib.Path])
1418
def test_git_constructor(
@@ -253,3 +257,228 @@ def test_git_init_make_parents(tmp_path: pathlib.Path) -> None:
253257
repo = git.Git(path=existing_path)
254258
result = repo.init(make_parents=False)
255259
assert "Initialized empty Git repository" in result
260+
261+
262+
# =============================================================================
263+
# GitBranchCmd Tests
264+
# =============================================================================
265+
266+
267+
class BranchDeleteFixture(t.NamedTuple):
268+
"""Test fixture for GitBranchCmd.delete() operations."""
269+
270+
test_id: str
271+
branch_name: str
272+
force: bool
273+
expect_success: bool
274+
275+
276+
BRANCH_DELETE_FIXTURES: list[BranchDeleteFixture] = [
277+
BranchDeleteFixture(
278+
test_id="delete-merged-branch",
279+
branch_name="feature-branch",
280+
force=False,
281+
expect_success=True,
282+
),
283+
BranchDeleteFixture(
284+
test_id="delete-branch-force",
285+
branch_name="force-delete-branch",
286+
force=True,
287+
expect_success=True,
288+
),
289+
]
290+
291+
292+
@pytest.mark.parametrize(
293+
list(BranchDeleteFixture._fields),
294+
BRANCH_DELETE_FIXTURES,
295+
ids=[test.test_id for test in BRANCH_DELETE_FIXTURES],
296+
)
297+
def test_branch_delete(
298+
git_repo: GitSync,
299+
test_id: str,
300+
branch_name: str,
301+
force: bool,
302+
expect_success: bool,
303+
) -> None:
304+
"""Test GitBranchCmd.delete() with various scenarios."""
305+
# Setup: create and checkout a branch, then switch back
306+
git_repo.cmd.branches.create(branch=branch_name)
307+
git_repo.cmd.checkout(branch="master")
308+
309+
# Get branch via Manager
310+
branch = git_repo.cmd.branches.get(branch_name=branch_name)
311+
assert branch is not None
312+
313+
# Delete the branch
314+
branch.delete(force=force)
315+
316+
# Verify deletion - get() raises ObjectDoesNotExist when not found
317+
with pytest.raises(ObjectDoesNotExist):
318+
git_repo.cmd.branches.get(branch_name=branch_name)
319+
320+
321+
class BranchRenameFixture(t.NamedTuple):
322+
"""Test fixture for GitBranchCmd.rename() operations."""
323+
324+
test_id: str
325+
original_name: str
326+
new_name: str
327+
force: bool
328+
329+
330+
BRANCH_RENAME_FIXTURES: list[BranchRenameFixture] = [
331+
BranchRenameFixture(
332+
test_id="rename-simple",
333+
original_name="old-branch",
334+
new_name="new-branch",
335+
force=False,
336+
),
337+
BranchRenameFixture(
338+
test_id="rename-with-force",
339+
original_name="rename-source",
340+
new_name="rename-target",
341+
force=True,
342+
),
343+
]
344+
345+
346+
@pytest.mark.parametrize(
347+
list(BranchRenameFixture._fields),
348+
BRANCH_RENAME_FIXTURES,
349+
ids=[test.test_id for test in BRANCH_RENAME_FIXTURES],
350+
)
351+
def test_branch_rename(
352+
git_repo: GitSync,
353+
test_id: str,
354+
original_name: str,
355+
new_name: str,
356+
force: bool,
357+
) -> None:
358+
"""Test GitBranchCmd.rename() with various scenarios."""
359+
# Setup: create a branch
360+
git_repo.cmd.branches.create(branch=original_name)
361+
git_repo.cmd.checkout(branch="master")
362+
363+
# Get branch and rename
364+
branch = git_repo.cmd.branches.get(branch_name=original_name)
365+
assert branch is not None
366+
branch.rename(new_name, force=force)
367+
368+
# Verify: old name gone (raises ObjectDoesNotExist), new name exists
369+
with pytest.raises(ObjectDoesNotExist):
370+
git_repo.cmd.branches.get(branch_name=original_name)
371+
assert git_repo.cmd.branches.get(branch_name=new_name) is not None
372+
373+
374+
class BranchCopyFixture(t.NamedTuple):
375+
"""Test fixture for GitBranchCmd.copy() operations."""
376+
377+
test_id: str
378+
source_name: str
379+
copy_name: str
380+
force: bool
381+
382+
383+
BRANCH_COPY_FIXTURES: list[BranchCopyFixture] = [
384+
BranchCopyFixture(
385+
test_id="copy-simple",
386+
source_name="source-branch",
387+
copy_name="copied-branch",
388+
force=False,
389+
),
390+
BranchCopyFixture(
391+
test_id="copy-with-force",
392+
source_name="copy-source",
393+
copy_name="copy-target",
394+
force=True,
395+
),
396+
]
397+
398+
399+
@pytest.mark.parametrize(
400+
list(BranchCopyFixture._fields),
401+
BRANCH_COPY_FIXTURES,
402+
ids=[test.test_id for test in BRANCH_COPY_FIXTURES],
403+
)
404+
def test_branch_copy(
405+
git_repo: GitSync,
406+
test_id: str,
407+
source_name: str,
408+
copy_name: str,
409+
force: bool,
410+
) -> None:
411+
"""Test GitBranchCmd.copy() with various scenarios."""
412+
# Setup: create a branch
413+
git_repo.cmd.branches.create(branch=source_name)
414+
git_repo.cmd.checkout(branch="master")
415+
416+
# Get branch and copy
417+
branch = git_repo.cmd.branches.get(branch_name=source_name)
418+
assert branch is not None
419+
branch.copy(copy_name, force=force)
420+
421+
# Verify: both branches exist
422+
assert git_repo.cmd.branches.get(branch_name=source_name) is not None
423+
assert git_repo.cmd.branches.get(branch_name=copy_name) is not None
424+
425+
426+
class BranchUpstreamFixture(t.NamedTuple):
427+
"""Test fixture for GitBranchCmd upstream operations."""
428+
429+
test_id: str
430+
branch_name: str
431+
upstream: str
432+
433+
434+
BRANCH_UPSTREAM_FIXTURES: list[BranchUpstreamFixture] = [
435+
BranchUpstreamFixture(
436+
test_id="set-upstream-origin-master",
437+
branch_name="tracking-branch",
438+
upstream="origin/master",
439+
),
440+
]
441+
442+
443+
@pytest.mark.parametrize(
444+
list(BranchUpstreamFixture._fields),
445+
BRANCH_UPSTREAM_FIXTURES,
446+
ids=[test.test_id for test in BRANCH_UPSTREAM_FIXTURES],
447+
)
448+
def test_branch_set_upstream(
449+
git_repo: GitSync,
450+
test_id: str,
451+
branch_name: str,
452+
upstream: str,
453+
) -> None:
454+
"""Test GitBranchCmd.set_upstream() with various scenarios."""
455+
# Setup: create a branch
456+
git_repo.cmd.branches.create(branch=branch_name)
457+
git_repo.cmd.checkout(branch="master")
458+
459+
# Get branch and set upstream
460+
branch = git_repo.cmd.branches.get(branch_name=branch_name)
461+
assert branch is not None
462+
result = branch.set_upstream(upstream)
463+
464+
# Verify: should succeed (output contains confirmation)
465+
assert "set up to track" in result.lower() or result == ""
466+
467+
468+
def test_branch_unset_upstream(git_repo: GitSync) -> None:
469+
"""Test GitBranchCmd.unset_upstream()."""
470+
branch_name = "untrack-branch"
471+
472+
# Setup: create a branch and set upstream
473+
git_repo.cmd.branches.create(branch=branch_name)
474+
git_repo.cmd.checkout(branch="master")
475+
476+
branch = git_repo.cmd.branches.get(branch_name=branch_name)
477+
assert branch is not None
478+
479+
# Set then unset upstream
480+
branch.set_upstream("origin/master")
481+
result = branch.unset_upstream()
482+
483+
# unset_upstream typically returns empty string on success
484+
assert result == "" or "upstream" not in result.lower()

0 commit comments

Comments
 (0)