test_diff.py
546 lines
| 15.9 KiB
| text/x-python
|
PythonLexer
r1 | # -*- coding: utf-8 -*- | |||
r1271 | # Copyright (C) 2010-2017 RhodeCode GmbH | |||
r1 | # | |||
# 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/ | ||||
import datetime | ||||
import pytest | ||||
from rhodecode.lib.vcs.nodes import FileNode | ||||
from rhodecode.tests.vcs.base import BackendTestMixin | ||||
class TestGetDiffValidation: | ||||
def test_raises_on_string_input(self, vcsbackend): | ||||
repo = vcsbackend.repo | ||||
with pytest.raises(TypeError): | ||||
repo.get_diff("1", "2") | ||||
def test_raises_if_commits_not_of_this_repository(self, vcsbackend): | ||||
repo = vcsbackend.repo | ||||
target_repo = vcsbackend.create_repo(number_of_commits=1) | ||||
repo_commit = repo[0] | ||||
wrong_commit = target_repo[0] | ||||
with pytest.raises(ValueError): | ||||
repo.get_diff(repo_commit, wrong_commit) | ||||
def test_allows_empty_commit(self, vcsbackend): | ||||
repo = vcsbackend.repo | ||||
commit = repo[0] | ||||
repo.get_diff(repo.EMPTY_COMMIT, commit) | ||||
def test_raise_if_both_commits_are_empty(self, vcsbackend): | ||||
repo = vcsbackend.repo | ||||
empty_commit = repo.EMPTY_COMMIT | ||||
with pytest.raises(ValueError): | ||||
repo.get_diff(empty_commit, empty_commit) | ||||
def test_supports_path1_parameter(self, vcsbackend): | ||||
repo = vcsbackend.repo | ||||
commit = repo[1] | ||||
repo.get_diff( | ||||
repo.EMPTY_COMMIT, commit, | ||||
path='vcs/__init__.py', path1='vcs/__init__.py') | ||||
@pytest.mark.backends("git", "hg") | ||||
def test_raises_value_error_if_paths_not_supported(self, vcsbackend): | ||||
repo = vcsbackend.repo | ||||
commit = repo[1] | ||||
with pytest.raises(ValueError): | ||||
repo.get_diff( | ||||
repo.EMPTY_COMMIT, commit, | ||||
path='trunk/example.py', path1='branches/argparse/example.py') | ||||
class TestRepositoryGetDiff(BackendTestMixin): | ||||
recreate_repo_per_test = False | ||||
@classmethod | ||||
def _get_commits(cls): | ||||
commits = [ | ||||
{ | ||||
'message': 'Initial commit', | ||||
'author': 'Joe Doe <joe.doe@example.com>', | ||||
'date': datetime.datetime(2010, 1, 1, 20), | ||||
'added': [ | ||||
FileNode('foobar', content='foobar'), | ||||
FileNode('foobar2', content='foobar2'), | ||||
], | ||||
}, | ||||
{ | ||||
'message': 'Changed foobar, added foobar3', | ||||
'author': 'Jane Doe <jane.doe@example.com>', | ||||
'date': datetime.datetime(2010, 1, 1, 21), | ||||
'added': [ | ||||
FileNode('foobar3', content='foobar3'), | ||||
], | ||||
'changed': [ | ||||
FileNode('foobar', 'FOOBAR'), | ||||
], | ||||
}, | ||||
{ | ||||
'message': 'Removed foobar, changed foobar3', | ||||
'author': 'Jane Doe <jane.doe@example.com>', | ||||
'date': datetime.datetime(2010, 1, 1, 22), | ||||
'changed': [ | ||||
FileNode('foobar3', content='FOOBAR\nFOOBAR\nFOOBAR\n'), | ||||
], | ||||
'removed': [FileNode('foobar')], | ||||
}, | ||||
{ | ||||
'message': 'Whitespace changes', | ||||
'author': 'Jane Doe <jane.doe@example.com>', | ||||
'date': datetime.datetime(2010, 1, 1, 23), | ||||
'changed': [ | ||||
FileNode('foobar3', content='FOOBAR \nFOOBAR\nFOOBAR\n'), | ||||
], | ||||
}, | ||||
] | ||||
return commits | ||||
def test_initial_commit_diff(self): | ||||
initial_commit = self.repo[0] | ||||
diff = self.repo.get_diff(self.repo.EMPTY_COMMIT, initial_commit) | ||||
assert diff.raw == self.first_commit_diffs[self.repo.alias] | ||||
def test_second_commit_diff(self): | ||||
diff = self.repo.get_diff(self.repo[0], self.repo[1]) | ||||
assert diff.raw == self.second_commit_diffs[self.repo.alias] | ||||
def test_third_commit_diff(self): | ||||
diff = self.repo.get_diff(self.repo[1], self.repo[2]) | ||||
assert diff.raw == self.third_commit_diffs[self.repo.alias] | ||||
def test_ignore_whitespace(self): | ||||
diff = self.repo.get_diff( | ||||
self.repo[2], self.repo[3], ignore_whitespace=True) | ||||
assert '@@' not in diff.raw | ||||
def test_only_one_file(self): | ||||
diff = self.repo.get_diff( | ||||
self.repo.EMPTY_COMMIT, self.repo[0], path='foobar') | ||||
assert 'foobar2' not in diff.raw | ||||
def test_context_parameter(self): | ||||
first_commit = self.repo.get_commit(commit_idx=0) | ||||
diff = self.repo.get_diff( | ||||
self.repo.EMPTY_COMMIT, first_commit, context=2) | ||||
assert diff.raw == self.first_commit_diffs[self.repo.alias] | ||||
def test_context_only_one_file(self): | ||||
diff = self.repo.get_diff( | ||||
self.repo.EMPTY_COMMIT, self.repo[0], path='foobar', context=2) | ||||
assert diff.raw == self.first_commit_one_file[self.repo.alias] | ||||
first_commit_diffs = { | ||||
'git': r"""diff --git a/foobar b/foobar | ||||
new file mode 100644 | ||||
index 0000000000000000000000000000000000000000..f6ea0495187600e7b2288c8ac19c5886383a4632 | ||||
--- /dev/null | ||||
+++ b/foobar | ||||
@@ -0,0 +1 @@ | ||||
+foobar | ||||
\ No newline at end of file | ||||
diff --git a/foobar2 b/foobar2 | ||||
new file mode 100644 | ||||
index 0000000000000000000000000000000000000000..e8c9d6b98e3dce993a464935e1a53f50b56a3783 | ||||
--- /dev/null | ||||
+++ b/foobar2 | ||||
@@ -0,0 +1 @@ | ||||
+foobar2 | ||||
\ No newline at end of file | ||||
""", | ||||
'hg': r"""diff --git a/foobar b/foobar | ||||
new file mode 100644 | ||||
--- /dev/null | ||||
+++ b/foobar | ||||
@@ -0,0 +1,1 @@ | ||||
+foobar | ||||
\ No newline at end of file | ||||
diff --git a/foobar2 b/foobar2 | ||||
new file mode 100644 | ||||
--- /dev/null | ||||
+++ b/foobar2 | ||||
@@ -0,0 +1,1 @@ | ||||
+foobar2 | ||||
\ No newline at end of file | ||||
""", | ||||
'svn': """Index: foobar | ||||
=================================================================== | ||||
diff --git a/foobar b/foobar | ||||
new file mode 10644 | ||||
--- /dev/null\t(revision 0) | ||||
+++ b/foobar\t(revision 1) | ||||
@@ -0,0 +1 @@ | ||||
+foobar | ||||
\\ No newline at end of file | ||||
Index: foobar2 | ||||
=================================================================== | ||||
diff --git a/foobar2 b/foobar2 | ||||
new file mode 10644 | ||||
--- /dev/null\t(revision 0) | ||||
+++ b/foobar2\t(revision 1) | ||||
@@ -0,0 +1 @@ | ||||
+foobar2 | ||||
\\ No newline at end of file | ||||
""", | ||||
} | ||||
second_commit_diffs = { | ||||
'git': r"""diff --git a/foobar b/foobar | ||||
index f6ea0495187600e7b2288c8ac19c5886383a4632..389865bb681b358c9b102d79abd8d5f941e96551 100644 | ||||
--- a/foobar | ||||
+++ b/foobar | ||||
@@ -1 +1 @@ | ||||
-foobar | ||||
\ No newline at end of file | ||||
+FOOBAR | ||||
\ No newline at end of file | ||||
diff --git a/foobar3 b/foobar3 | ||||
new file mode 100644 | ||||
index 0000000000000000000000000000000000000000..c11c37d41d33fb47741cff93fa5f9d798c1535b0 | ||||
--- /dev/null | ||||
+++ b/foobar3 | ||||
@@ -0,0 +1 @@ | ||||
+foobar3 | ||||
\ No newline at end of file | ||||
""", | ||||
'hg': r"""diff --git a/foobar b/foobar | ||||
--- a/foobar | ||||
+++ b/foobar | ||||
@@ -1,1 +1,1 @@ | ||||
-foobar | ||||
\ No newline at end of file | ||||
+FOOBAR | ||||
\ No newline at end of file | ||||
diff --git a/foobar3 b/foobar3 | ||||
new file mode 100644 | ||||
--- /dev/null | ||||
+++ b/foobar3 | ||||
@@ -0,0 +1,1 @@ | ||||
+foobar3 | ||||
\ No newline at end of file | ||||
""", | ||||
'svn': """Index: foobar | ||||
=================================================================== | ||||
diff --git a/foobar b/foobar | ||||
--- a/foobar\t(revision 1) | ||||
+++ b/foobar\t(revision 2) | ||||
@@ -1 +1 @@ | ||||
-foobar | ||||
\\ No newline at end of file | ||||
+FOOBAR | ||||
\\ No newline at end of file | ||||
Index: foobar3 | ||||
=================================================================== | ||||
diff --git a/foobar3 b/foobar3 | ||||
new file mode 10644 | ||||
--- /dev/null\t(revision 0) | ||||
+++ b/foobar3\t(revision 2) | ||||
@@ -0,0 +1 @@ | ||||
+foobar3 | ||||
\\ No newline at end of file | ||||
""", | ||||
} | ||||
third_commit_diffs = { | ||||
'git': r"""diff --git a/foobar b/foobar | ||||
deleted file mode 100644 | ||||
index 389865bb681b358c9b102d79abd8d5f941e96551..0000000000000000000000000000000000000000 | ||||
--- a/foobar | ||||
+++ /dev/null | ||||
@@ -1 +0,0 @@ | ||||
-FOOBAR | ||||
\ No newline at end of file | ||||
diff --git a/foobar3 b/foobar3 | ||||
index c11c37d41d33fb47741cff93fa5f9d798c1535b0..f9324477362684ff692aaf5b9a81e01b9e9a671c 100644 | ||||
--- a/foobar3 | ||||
+++ b/foobar3 | ||||
@@ -1 +1,3 @@ | ||||
-foobar3 | ||||
\ No newline at end of file | ||||
+FOOBAR | ||||
+FOOBAR | ||||
+FOOBAR | ||||
""", | ||||
'hg': r"""diff --git a/foobar b/foobar | ||||
deleted file mode 100644 | ||||
--- a/foobar | ||||
+++ /dev/null | ||||
@@ -1,1 +0,0 @@ | ||||
-FOOBAR | ||||
\ No newline at end of file | ||||
diff --git a/foobar3 b/foobar3 | ||||
--- a/foobar3 | ||||
+++ b/foobar3 | ||||
@@ -1,1 +1,3 @@ | ||||
-foobar3 | ||||
\ No newline at end of file | ||||
+FOOBAR | ||||
+FOOBAR | ||||
+FOOBAR | ||||
""", | ||||
'svn': """Index: foobar | ||||
=================================================================== | ||||
diff --git a/foobar b/foobar | ||||
deleted file mode 10644 | ||||
--- a/foobar\t(revision 2) | ||||
+++ /dev/null\t(revision 3) | ||||
@@ -1 +0,0 @@ | ||||
-FOOBAR | ||||
\\ No newline at end of file | ||||
Index: foobar3 | ||||
=================================================================== | ||||
diff --git a/foobar3 b/foobar3 | ||||
--- a/foobar3\t(revision 2) | ||||
+++ b/foobar3\t(revision 3) | ||||
@@ -1 +1,3 @@ | ||||
-foobar3 | ||||
\\ No newline at end of file | ||||
+FOOBAR | ||||
+FOOBAR | ||||
+FOOBAR | ||||
""", | ||||
} | ||||
first_commit_one_file = { | ||||
'git': r"""diff --git a/foobar b/foobar | ||||
new file mode 100644 | ||||
index 0000000000000000000000000000000000000000..f6ea0495187600e7b2288c8ac19c5886383a4632 | ||||
--- /dev/null | ||||
+++ b/foobar | ||||
@@ -0,0 +1 @@ | ||||
+foobar | ||||
\ No newline at end of file | ||||
""", | ||||
'hg': r"""diff --git a/foobar b/foobar | ||||
new file mode 100644 | ||||
--- /dev/null | ||||
+++ b/foobar | ||||
@@ -0,0 +1,1 @@ | ||||
+foobar | ||||
\ No newline at end of file | ||||
""", | ||||
'svn': """Index: foobar | ||||
=================================================================== | ||||
diff --git a/foobar b/foobar | ||||
new file mode 10644 | ||||
--- /dev/null\t(revision 0) | ||||
+++ b/foobar\t(revision 1) | ||||
@@ -0,0 +1 @@ | ||||
+foobar | ||||
\\ No newline at end of file | ||||
""", | ||||
} | ||||
class TestSvnGetDiff: | ||||
@pytest.mark.parametrize('path, path1', [ | ||||
('trunk/example.py', 'tags/v0.2/example.py'), | ||||
('trunk', 'tags/v0.2') | ||||
], ids=['file', 'dir']) | ||||
def test_diff_to_tagged_version(self, vcsbackend_svn, path, path1): | ||||
repo = vcsbackend_svn['svn-simple-layout'] | ||||
r1259 | commit1 = repo[-2] | |||
commit2 = repo[-1] | ||||
diff = repo.get_diff(commit1, commit2, path=path, path1=path1) | ||||
r1 | assert diff.raw == self.expected_diff_v_0_2 | |||
expected_diff_v_0_2 = '''Index: example.py | ||||
=================================================================== | ||||
diff --git a/example.py b/example.py | ||||
r1259 | --- a/example.py\t(revision 25) | |||
r1 | +++ b/example.py\t(revision 26) | |||
@@ -7,8 +7,12 @@ | ||||
@click.command() | ||||
def main(): | ||||
+ """ | ||||
+ Will print out a useful message on invocation. | ||||
+ """ | ||||
click.echo("Hello world!") | ||||
+# Main entry point | ||||
if __name__ == '__main__': | ||||
main() | ||||
''' | ||||
def test_diff_of_moved_directory(self, vcsbackend_svn): | ||||
repo = vcsbackend_svn['svn-move-directory'] | ||||
diff = repo.get_diff(repo[0], repo[1]) | ||||
# TODO: johbo: Think about supporting svn directory nodes | ||||
# a little bit better, source is here like a file | ||||
expected_diff = """Index: source | ||||
=================================================================== | ||||
diff --git a/source b/source | ||||
deleted file mode 10644 | ||||
--- a/source\t(revision 1) | ||||
+++ /dev/null\t(revision 2) | ||||
Index: target/file | ||||
=================================================================== | ||||
diff --git a/target/file b/target/file | ||||
new file mode 10644 | ||||
--- /dev/null\t(revision 0) | ||||
+++ b/target/file\t(revision 2) | ||||
""" | ||||
assert diff.raw == expected_diff | ||||
class TestGetDiffBinary(BackendTestMixin): | ||||
recreate_repo_per_test = False | ||||
# Note: "Fake" PNG files, has the correct magic as prefix | ||||
BINARY = """\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00""" | ||||
BINARY2 = """\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x01\x00\x00""" | ||||
@staticmethod | ||||
def _get_commits(): | ||||
commits = [ | ||||
{ | ||||
'message': 'Add binary file image.png', | ||||
'author': 'Joe Doe <joe.deo@example.com>', | ||||
'date': datetime.datetime(2010, 1, 1, 20), | ||||
'added': [ | ||||
FileNode('image.png', content=TestGetDiffBinary.BINARY), | ||||
]}, | ||||
{ | ||||
'message': 'Modify image.png', | ||||
'author': 'Joe Doe <joe.deo@example.com>', | ||||
'date': datetime.datetime(2010, 1, 1, 21), | ||||
'changed': [ | ||||
FileNode('image.png', content=TestGetDiffBinary.BINARY2), | ||||
]}, | ||||
{ | ||||
'message': 'Remove image.png', | ||||
'author': 'Joe Doe <joe.deo@example.com>', | ||||
'date': datetime.datetime(2010, 1, 1, 21), | ||||
'removed': [ | ||||
FileNode('image.png'), | ||||
]}, | ||||
] | ||||
return commits | ||||
def test_add_a_binary_file(self): | ||||
diff = self.repo.get_diff(self.repo.EMPTY_COMMIT, self.repo[0]) | ||||
expected = { | ||||
'git': """diff --git a/image.png b/image.png | ||||
new file mode 100644 | ||||
index 0000000000000000000000000000000000000000..28380fd4a25c58be1b68b523ba2a314f4459ee9c | ||||
GIT binary patch | ||||
literal 19 | ||||
YcmeAS@N?(olHy`uVBq!ia0vp^03%2O-T(jq | ||||
literal 0 | ||||
HcmV?d00001 | ||||
""", | ||||
'hg': """diff --git a/image.png b/image.png | ||||
new file mode 100644 | ||||
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..28380fd4a25c58be1b68b523ba2a314f4459ee9c | ||||
GIT binary patch | ||||
literal 19 | ||||
Yc%17D@N?(olHy`uVBq!ia0vp^03%2O-T(jq | ||||
""", | ||||
'svn': """=================================================================== | ||||
Cannot display: file marked as a binary type. | ||||
svn:mime-type = application/octet-stream | ||||
Index: image.png | ||||
=================================================================== | ||||
diff --git a/image.png b/image.png | ||||
new file mode 10644 | ||||
--- /dev/null\t(revision 0) | ||||
+++ b/image.png\t(revision 1) | ||||
""", | ||||
} | ||||
assert diff.raw == expected[self.repo.alias] | ||||
def test_update_a_binary_file(self): | ||||
diff = self.repo.get_diff(self.repo[0], self.repo[1]) | ||||
expected = { | ||||
'git': """diff --git a/image.png b/image.png | ||||
index 28380fd4a25c58be1b68b523ba2a314f4459ee9c..1008a77cd372386a1c24fbd96019333f67ad0065 100644 | ||||
GIT binary patch | ||||
literal 19 | ||||
acmeAS@N?(olHy`uVBq!ia0y~$U;qFkO9I~j | ||||
literal 19 | ||||
YcmeAS@N?(olHy`uVBq!ia0vp^03%2O-T(jq | ||||
""", | ||||
'hg': """diff --git a/image.png b/image.png | ||||
index 28380fd4a25c58be1b68b523ba2a314f4459ee9c..1008a77cd372386a1c24fbd96019333f67ad0065 | ||||
GIT binary patch | ||||
literal 19 | ||||
ac%17D@N?(olHy`uVBq!ia0y~$U;qFkO9I~j | ||||
""", | ||||
'svn': """=================================================================== | ||||
Cannot display: file marked as a binary type. | ||||
svn:mime-type = application/octet-stream | ||||
Index: image.png | ||||
=================================================================== | ||||
diff --git a/image.png b/image.png | ||||
--- a/image.png\t(revision 1) | ||||
+++ b/image.png\t(revision 2) | ||||
""", | ||||
} | ||||
assert diff.raw == expected[self.repo.alias] | ||||
def test_remove_a_binary_file(self): | ||||
diff = self.repo.get_diff(self.repo[1], self.repo[2]) | ||||
expected = { | ||||
'git': """diff --git a/image.png b/image.png | ||||
deleted file mode 100644 | ||||
index 1008a77cd372386a1c24fbd96019333f67ad0065..0000000000000000000000000000000000000000 | ||||
GIT binary patch | ||||
literal 0 | ||||
HcmV?d00001 | ||||
literal 19 | ||||
acmeAS@N?(olHy`uVBq!ia0y~$U;qFkO9I~j | ||||
""", | ||||
'hg': """diff --git a/image.png b/image.png | ||||
deleted file mode 100644 | ||||
index 1008a77cd372386a1c24fbd96019333f67ad0065..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 | ||||
GIT binary patch | ||||
literal 0 | ||||
Hc$@<O00001 | ||||
""", | ||||
'svn': """=================================================================== | ||||
Cannot display: file marked as a binary type. | ||||
svn:mime-type = application/octet-stream | ||||
Index: image.png | ||||
=================================================================== | ||||
diff --git a/image.png b/image.png | ||||
deleted file mode 10644 | ||||
--- a/image.png\t(revision 2) | ||||
+++ /dev/null\t(revision 3) | ||||
""", | ||||
} | ||||
assert diff.raw == expected[self.repo.alias] | ||||