diff options
Diffstat (limited to '')
-rw-r--r-- | tests/check_merge_conflict_test.py | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/tests/check_merge_conflict_test.py b/tests/check_merge_conflict_test.py new file mode 100644 index 0000000..76c4283 --- /dev/null +++ b/tests/check_merge_conflict_test.py @@ -0,0 +1,157 @@ +from __future__ import annotations + +import os +import shutil + +import pytest + +from pre_commit_hooks.check_merge_conflict import main +from pre_commit_hooks.util import cmd_output +from testing.util import get_resource_path +from testing.util import git_commit + + +@pytest.fixture +def f1_is_a_conflict_file(tmpdir): + # Make a merge conflict + repo1 = tmpdir.join('repo1') + repo1_f1 = repo1.join('f1') + repo2 = tmpdir.join('repo2') + repo2_f1 = repo2.join('f1') + + cmd_output('git', 'init', '--', str(repo1)) + with repo1.as_cwd(): + repo1_f1.ensure() + cmd_output('git', 'add', '.') + git_commit('-m', 'commit1') + + cmd_output('git', 'clone', str(repo1), str(repo2)) + + # Commit in master + with repo1.as_cwd(): + repo1_f1.write('parent\n') + git_commit('-am', 'master commit2') + + # Commit in clone and pull + with repo2.as_cwd(): + repo2_f1.write('child\n') + git_commit('-am', 'clone commit2') + cmd_output('git', 'pull', '--no-rebase', retcode=None) + # We should end up in a merge conflict! + f1 = repo2_f1.read() + assert f1.startswith( + '<<<<<<< HEAD\n' + 'child\n' + '=======\n' + 'parent\n' + '>>>>>>>', + ) or f1.startswith( + '<<<<<<< HEAD\n' + 'child\n' + # diff3 conflict style git merges add this line: + '||||||| merged common ancestors\n' + '=======\n' + 'parent\n' + '>>>>>>>', + ) or f1.startswith( + # .gitconfig with [pull] rebase = preserve causes a rebase which + # flips parent / child + '<<<<<<< HEAD\n' + 'parent\n' + '=======\n' + 'child\n' + '>>>>>>>', + ) + assert os.path.exists(os.path.join('.git', 'MERGE_MSG')) + yield repo2 + + +@pytest.fixture +def repository_pending_merge(tmpdir): + # Make a (non-conflicting) merge + repo1 = tmpdir.join('repo1') + repo1_f1 = repo1.join('f1') + repo2 = tmpdir.join('repo2') + repo2_f1 = repo2.join('f1') + repo2_f2 = repo2.join('f2') + cmd_output('git', 'init', str(repo1)) + with repo1.as_cwd(): + repo1_f1.ensure() + cmd_output('git', 'add', '.') + git_commit('-m', 'commit1') + + cmd_output('git', 'clone', str(repo1), str(repo2)) + + # Commit in master + with repo1.as_cwd(): + repo1_f1.write('parent\n') + git_commit('-am', 'master commit2') + + # Commit in clone and pull without committing + with repo2.as_cwd(): + repo2_f2.write('child\n') + cmd_output('git', 'add', '.') + git_commit('-m', 'clone commit2') + cmd_output('git', 'pull', '--no-commit', '--no-rebase') + # We should end up in a pending merge + assert repo2_f1.read() == 'parent\n' + assert repo2_f2.read() == 'child\n' + assert os.path.exists(os.path.join('.git', 'MERGE_HEAD')) + yield repo2 + + +@pytest.mark.usefixtures('f1_is_a_conflict_file') +def test_merge_conflicts_git(capsys): + assert main(['f1']) == 1 + out, _ = capsys.readouterr() + assert out == ( + "f1:1: Merge conflict string '<<<<<<<' found\n" + "f1:3: Merge conflict string '=======' found\n" + "f1:5: Merge conflict string '>>>>>>>' found\n" + ) + + +@pytest.mark.parametrize( + 'contents', (b'<<<<<<< HEAD\n', b'=======\n', b'>>>>>>> master\n'), +) +def test_merge_conflicts_failing(contents, repository_pending_merge): + repository_pending_merge.join('f2').write_binary(contents) + assert main(['f2']) == 1 + + +@pytest.mark.parametrize( + 'contents', (b'# <<<<<<< HEAD\n', b'# =======\n', b'import mod', b''), +) +def test_merge_conflicts_ok(contents, f1_is_a_conflict_file): + f1_is_a_conflict_file.join('f1').write_binary(contents) + assert main(['f1']) == 0 + + +@pytest.mark.usefixtures('f1_is_a_conflict_file') +def test_ignores_binary_files(): + shutil.copy(get_resource_path('img1.jpg'), 'f1') + assert main(['f1']) == 0 + + +def test_does_not_care_when_not_in_a_merge(tmpdir): + f = tmpdir.join('README.md') + f.write_binary(b'problem\n=======\n') + assert main([str(f.realpath())]) == 0 + + +def test_care_when_assumed_merge(tmpdir): + f = tmpdir.join('README.md') + f.write_binary(b'problem\n=======\n') + assert main([str(f.realpath()), '--assume-in-merge']) == 1 + + +def test_worktree_merge_conflicts(f1_is_a_conflict_file, tmpdir, capsys): + worktree = tmpdir.join('worktree') + cmd_output('git', 'worktree', 'add', str(worktree)) + with worktree.as_cwd(): + cmd_output( + 'git', 'pull', '--no-rebase', 'origin', 'master', retcode=None, + ) + msg = f1_is_a_conflict_file.join('.git/worktrees/worktree/MERGE_MSG') + assert msg.exists() + test_merge_conflicts_git(capsys) |