|
|
|
|
|
# Copyright (C) 2010-2023 RhodeCode GmbH
|
|
|
#
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
# it under the terms of the GNU Affero General Public License, version 3
|
|
|
# (only), as published by the Free Software Foundation.
|
|
|
#
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
# GNU General Public License for more details.
|
|
|
#
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
#
|
|
|
# This program is dual-licensed. If you wish to learn more about the
|
|
|
# RhodeCode Enterprise Edition, including its added features, Support services,
|
|
|
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
|
|
|
|
|
"""
|
|
|
Tests of :mod:`rhodecode.lib.diffs` around the context of a specific line.
|
|
|
"""
|
|
|
|
|
|
import textwrap
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
from rhodecode.lib import diffs
|
|
|
from rhodecode.lib.str_utils import safe_bytes
|
|
|
from rhodecode.lib.vcs.backends.git.diff import GitDiff
|
|
|
|
|
|
|
|
|
def test_context_of_new_and_old_line_number_raises(diff_processor):
|
|
|
with pytest.raises(ValueError):
|
|
|
diff_processor.get_context_of_line(
|
|
|
path='file.txt', diff_line=diffs.DiffLineNumber(old=7, new=7))
|
|
|
|
|
|
|
|
|
def test_context_of_an_old_line_number(diff_processor):
|
|
|
context = diff_processor.get_context_of_line(
|
|
|
path='file.txt', diff_line=diffs.DiffLineNumber(old=7, new=None))
|
|
|
expected_context = [
|
|
|
('unmod', b'line04\n'),
|
|
|
('unmod', b'line05\n'),
|
|
|
('unmod', b'line06\n'),
|
|
|
('unmod', b'line07\n'),
|
|
|
('add', b'line07a Add after line07\n'),
|
|
|
('unmod', b'line08\n'),
|
|
|
('unmod', b'line09\n'),
|
|
|
]
|
|
|
assert context == expected_context
|
|
|
|
|
|
|
|
|
def test_context_of_a_new_line_number(diff_processor):
|
|
|
context = diff_processor.get_context_of_line(
|
|
|
path='file.txt', diff_line=diffs.DiffLineNumber(old=None, new=8))
|
|
|
expected_context = [
|
|
|
('unmod', b'line05\n'),
|
|
|
('unmod', b'line06\n'),
|
|
|
('unmod', b'line07\n'),
|
|
|
('add', b'line07a Add after line07\n'),
|
|
|
('unmod', b'line08\n'),
|
|
|
('unmod', b'line09\n'),
|
|
|
('unmod', b'line10\n'),
|
|
|
]
|
|
|
assert context == expected_context
|
|
|
|
|
|
|
|
|
def test_context_of_an_invisible_line_beginning_of_hunk(diff_processor):
|
|
|
# Note: The caller has to pass in a diff which is suitable to satisfy
|
|
|
# its requirements. This test just ensures that we see a sane behavior.
|
|
|
context = diff_processor.get_context_of_line(
|
|
|
path='file.txt', diff_line=diffs.DiffLineNumber(old=None, new=3))
|
|
|
expected_context = [
|
|
|
('unmod', b'line02\n'),
|
|
|
('unmod', b'line03\n'),
|
|
|
('unmod', b'line04\n'),
|
|
|
('unmod', b'line05\n'),
|
|
|
('unmod', b'line06\n'),
|
|
|
]
|
|
|
assert context == expected_context
|
|
|
|
|
|
|
|
|
def test_context_of_an_invisible_line_end_of_hunk(diff_processor):
|
|
|
# Note: The caller has to pass in a diff which is suitable to satisfy
|
|
|
# its requirements. This test just ensures that we see a sane behavior.
|
|
|
context = diff_processor.get_context_of_line(
|
|
|
path='file.txt', diff_line=diffs.DiffLineNumber(old=12, new=None))
|
|
|
expected_context = [
|
|
|
('unmod', b'line09\n'),
|
|
|
('unmod', b'line10\n'),
|
|
|
('unmod', b'line11\n'),
|
|
|
('unmod', b'line12\n'),
|
|
|
('unmod', b'line13\n'),
|
|
|
]
|
|
|
assert context == expected_context
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('diff_fixture', ['change-in-beginning.diff'])
|
|
|
def test_context_of_an_incomplete_hunk_in_the_beginning(diff_processor):
|
|
|
context = diff_processor.get_context_of_line(
|
|
|
path='file.txt', diff_line=diffs.DiffLineNumber(old=None, new=2))
|
|
|
expected_context = [
|
|
|
('unmod', b'line01\n'),
|
|
|
('add', b'line01a Add line after line01\n'),
|
|
|
('unmod', b'line02\n'),
|
|
|
('unmod', b'line03\n'),
|
|
|
('unmod', b'line04\n'),
|
|
|
]
|
|
|
assert context == expected_context
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('diff_fixture', ['change-in-end.diff'])
|
|
|
def test_context_of_an_incomplete_hunk_in_the_end(diff_processor):
|
|
|
context = diff_processor.get_context_of_line(
|
|
|
path='file.txt', diff_line=diffs.DiffLineNumber(old=None, new=80))
|
|
|
expected_context = [
|
|
|
('unmod', b'line36\n'),
|
|
|
('unmod', b'line37\n'),
|
|
|
('unmod', b'line38\n'),
|
|
|
('add', b'line38a Add line after line38\n'),
|
|
|
('unmod', b'line39\n'),
|
|
|
]
|
|
|
assert context == expected_context
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('diff_fixture', [
|
|
|
'single-line.diff',
|
|
|
'single-line-two-files.diff',
|
|
|
])
|
|
|
def test_appends_newline_for_each_context_line(diff_processor):
|
|
|
context = diff_processor.get_context_of_line(
|
|
|
path='file_b', diff_line=diffs.DiffLineNumber(old=None, new=1))
|
|
|
assert context == [('add', b'test_content\n')]
|
|
|
|
|
|
|
|
|
def test_context_of_a_missing_line_raises(diff_processor):
|
|
|
missing_line = 20
|
|
|
with pytest.raises(diffs.LineNotInDiffException):
|
|
|
diff_processor.get_context_of_line(
|
|
|
path='file.txt',
|
|
|
diff_line=diffs.DiffLineNumber(old=None, new=missing_line))
|
|
|
|
|
|
|
|
|
def test_context_of_a_missing_file_raises(diff_processor):
|
|
|
with pytest.raises(diffs.FileNotInDiffException):
|
|
|
diff_processor.get_context_of_line(
|
|
|
path='not_existing_file.txt',
|
|
|
diff_line=diffs.DiffLineNumber(old=None, new=8))
|
|
|
|
|
|
|
|
|
def test_find_context_with_full_context(diff_processor):
|
|
|
context_of_line_7 = [
|
|
|
('unmod', b'line05\n'),
|
|
|
('unmod', b'line06\n'),
|
|
|
('unmod', b'line07\n'),
|
|
|
('add', b'line07a Add after line07\n'),
|
|
|
('unmod', b'line08\n'),
|
|
|
('unmod', b'line09\n'),
|
|
|
('unmod', b'line10\n'),
|
|
|
]
|
|
|
found_line = diff_processor.find_context(
|
|
|
'file.txt', context_of_line_7, offset=3)
|
|
|
assert found_line == [diffs.DiffLineNumber(old=None, new=8)]
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('diff_fixture', ['change-duplicated.diff'])
|
|
|
def test_find_context_multiple_times(diff_processor):
|
|
|
context = [
|
|
|
('unmod', b'line04\n'),
|
|
|
('unmod', b'line05\n'),
|
|
|
('unmod', b'line06\n'),
|
|
|
('add', b'line06a add line\n'),
|
|
|
('unmod', b'line07\n'),
|
|
|
('unmod', b'line08\n'),
|
|
|
('unmod', b'line09\n'),
|
|
|
]
|
|
|
found_line = diff_processor.find_context('file.txt', context, offset=3)
|
|
|
assert found_line == [
|
|
|
diffs.DiffLineNumber(old=None, new=7),
|
|
|
diffs.DiffLineNumber(old=None, new=49),
|
|
|
]
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('offset', [20, -20, -1, 7])
|
|
|
def test_find_context_offset_param_raises(diff_processor, offset):
|
|
|
context_of_line_7 = [
|
|
|
('unmod', b'line04\n'),
|
|
|
('unmod', b'line05\n'),
|
|
|
('unmod', b'line06\n'),
|
|
|
('unmod', b'line07\n'),
|
|
|
('add', b'line07a Add after line07\n'),
|
|
|
('unmod', b'line08\n'),
|
|
|
('unmod', b'line09\n'),
|
|
|
]
|
|
|
with pytest.raises(ValueError):
|
|
|
diff_processor.find_context(
|
|
|
'file.txt', context_of_line_7, offset=offset)
|
|
|
|
|
|
|
|
|
def test_find_context_beginning_of_chunk(diff_processor):
|
|
|
context_of_first_line = [
|
|
|
('unmod', b'line02\n'),
|
|
|
('unmod', b'line03\n'),
|
|
|
('unmod', b'line04\n'),
|
|
|
('unmod', b'line05\n'),
|
|
|
]
|
|
|
found_line = diff_processor.find_context(
|
|
|
'file.txt', context_of_first_line, offset=0)
|
|
|
assert found_line == [diffs.DiffLineNumber(old=2, new=2)]
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('diff_fixture', ['change-in-beginning.diff'])
|
|
|
def test_find_context_beginning_of_file(diff_processor):
|
|
|
context_of_first_line = [
|
|
|
('add', b'line01a Add line after line01\n'),
|
|
|
('unmod', b'line02\n'),
|
|
|
('unmod', b'line03\n'),
|
|
|
('unmod', b'line04\n'),
|
|
|
('unmod', b'line05\n'),
|
|
|
('unmod', b'line06\n'),
|
|
|
('unmod', b'line07\n'),
|
|
|
]
|
|
|
found_line = diff_processor.find_context(
|
|
|
'file.txt', context_of_first_line, offset=3)
|
|
|
assert found_line == [diffs.DiffLineNumber(old=4, new=5)]
|
|
|
|
|
|
|
|
|
def test_find_context_end_of_chunk(diff_processor):
|
|
|
context_of_last_line = [
|
|
|
('unmod', b'line10\n'),
|
|
|
('unmod', b'line11\n'),
|
|
|
('unmod', b'line12\n'),
|
|
|
('unmod', b'line13\n'),
|
|
|
]
|
|
|
found_line = diff_processor.find_context(
|
|
|
'file.txt', context_of_last_line, offset=3)
|
|
|
assert found_line == [diffs.DiffLineNumber(old=13, new=14)]
|
|
|
|
|
|
|
|
|
@pytest.fixture()
|
|
|
def diff_processor(request, diff_fixture):
|
|
|
raw_diff = diffs_store[diff_fixture]
|
|
|
diff = GitDiff(raw_diff)
|
|
|
processor = diffs.DiffProcessor(diff, diff_format='newdiff')
|
|
|
processor.prepare()
|
|
|
return processor
|
|
|
|
|
|
|
|
|
@pytest.fixture()
|
|
|
def diff_fixture():
|
|
|
return 'default.diff'
|
|
|
|
|
|
|
|
|
diff_default: bytes = safe_bytes(textwrap.dedent("""
|
|
|
diff --git a/file.txt b/file.txt
|
|
|
index 76e4f2e..6f8738f 100644
|
|
|
--- a/file.txt
|
|
|
+++ b/file.txt
|
|
|
@@ -2,12 +2,13 @@ line01
|
|
|
line02
|
|
|
line03
|
|
|
line04
|
|
|
line05
|
|
|
line06
|
|
|
line07
|
|
|
+line07a Add after line07
|
|
|
line08
|
|
|
line09
|
|
|
line10
|
|
|
line11
|
|
|
line12
|
|
|
line13
|
|
|
"""))
|
|
|
|
|
|
|
|
|
diff_beginning: bytes = safe_bytes(textwrap.dedent("""
|
|
|
diff --git a/file.txt b/file.txt
|
|
|
index 76e4f2e..47d39f4 100644
|
|
|
--- a/file.txt
|
|
|
+++ b/file.txt
|
|
|
@@ -1,7 +1,8 @@
|
|
|
line01
|
|
|
+line01a Add line after line01
|
|
|
line02
|
|
|
line03
|
|
|
line04
|
|
|
line05
|
|
|
line06
|
|
|
line07
|
|
|
"""))
|
|
|
|
|
|
|
|
|
diff_end: bytes = safe_bytes(textwrap.dedent("""
|
|
|
diff --git a/file.txt b/file.txt
|
|
|
index 76e4f2e..b1304db 100644
|
|
|
--- a/file.txt
|
|
|
+++ b/file.txt
|
|
|
@@ -74,7 +74,8 @@ line32
|
|
|
line33
|
|
|
line34
|
|
|
line35
|
|
|
line36
|
|
|
line37
|
|
|
line38
|
|
|
+line38a Add line after line38
|
|
|
line39
|
|
|
"""))
|
|
|
|
|
|
|
|
|
diff_duplicated_change: bytes = safe_bytes(textwrap.dedent("""
|
|
|
diff --git a/file.txt b/file.txt
|
|
|
index 76e4f2e..55c2781 100644
|
|
|
--- a/file.txt
|
|
|
+++ b/file.txt
|
|
|
@@ -1,12 +1,13 @@
|
|
|
line01
|
|
|
line02
|
|
|
line03
|
|
|
line04
|
|
|
line05
|
|
|
line06
|
|
|
+line06a add line
|
|
|
line07
|
|
|
line08
|
|
|
line09
|
|
|
line10
|
|
|
line11
|
|
|
line12
|
|
|
@@ -42,12 +43,13 @@ line39
|
|
|
line01
|
|
|
line02
|
|
|
line03
|
|
|
line04
|
|
|
line05
|
|
|
line06
|
|
|
+line06a add line
|
|
|
line07
|
|
|
line08
|
|
|
line09
|
|
|
line10
|
|
|
line11
|
|
|
line12
|
|
|
"""))
|
|
|
|
|
|
|
|
|
diff_single_line: bytes = safe_bytes(textwrap.dedent("""
|
|
|
diff --git a/file_b b/file_b
|
|
|
new file mode 100644
|
|
|
index 00000000..915e94ff
|
|
|
--- /dev/null
|
|
|
+++ b/file_b
|
|
|
@@ -0,0 +1 @@
|
|
|
+test_content
|
|
|
"""))
|
|
|
|
|
|
|
|
|
diff_single_line_two_files: bytes = safe_bytes(textwrap.dedent("""
|
|
|
diff --git a/file_b b/file_b
|
|
|
new file mode 100644
|
|
|
index 00000000..915e94ff
|
|
|
--- /dev/null
|
|
|
+++ b/file_b
|
|
|
@@ -0,0 +1 @@
|
|
|
+test_content
|
|
|
diff --git a/file_c b/file_c
|
|
|
new file mode 100644
|
|
|
index 00000000..915e94ff
|
|
|
--- /dev/null
|
|
|
+++ b/file_c
|
|
|
@@ -0,0 +1 @@
|
|
|
+test_content
|
|
|
"""))
|
|
|
|
|
|
|
|
|
diffs_store = {
|
|
|
'default.diff': diff_default,
|
|
|
'change-in-beginning.diff': diff_beginning,
|
|
|
'change-in-end.diff': diff_end,
|
|
|
'change-duplicated.diff': diff_duplicated_change,
|
|
|
'single-line.diff': diff_single_line,
|
|
|
'single-line-two-files.diff': diff_single_line_two_files,
|
|
|
}
|
|
|
|