summaryrefslogtreecommitdiffstats
path: root/tests/check_merge_conflict_test.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-21 20:47:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-21 20:47:18 +0000
commitceb85610c77b7487b0b7d742415301922c6b13b6 (patch)
tree82456c5d0bc77961759812ddd85414435ba89127 /tests/check_merge_conflict_test.py
parentInitial commit. (diff)
downloadpre-commit-hooks-upstream.tar.xz
pre-commit-hooks-upstream.zip
Adding upstream version 4.5.0+dfsg.upstream/4.5.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/check_merge_conflict_test.py')
-rw-r--r--tests/check_merge_conflict_test.py157
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)