class GitTests(SpyAgency, SCMTestCase): """Unit tests for Git.""" fixtures = ["test_scmtools"] def setUp(self): super(GitTests, self).setUp() tool = Tool.objects.get(name="Git") self.local_repo_path = os.path.join(os.path.dirname(__file__), "..", "testdata", "git_repo") self.git_ssh_path = "localhost:%s" % self.local_repo_path.replace("\\", "/") remote_repo_path = "[email protected]:reviewboard/reviewboard.git" remote_repo_raw_url = "http://github.com/api/v2/yaml/blob/show/" "reviewboard/reviewboard/<revision>" self.repository = Repository(name="Git test repo", path=self.local_repo_path, tool=tool) self.remote_repository = Repository( name="Remote Git test repo", path=remote_repo_path, raw_file_url=remote_repo_raw_url, tool=tool ) try: self.tool = self.repository.get_scmtool() self.remote_tool = self.remote_repository.get_scmtool() except ImportError: raise nose.SkipTest("git binary not found") def _read_fixture(self, filename): filename = os.path.join(os.path.dirname(__file__), "..", "testdata", filename) with open(filename, "r") as f: return f.read() def _get_file_in_diff(self, diff, filenum=0): files = self.tool.get_parser(diff).parse() self.assertTrue(filenum < len(files)) return files[filenum] def test_ssh(self): """Testing a SSH-backed git repository""" self._test_ssh(self.git_ssh_path) def test_ssh_with_site(self): """Testing a SSH-backed git repository with a LocalSite""" self._test_ssh_with_site(self.git_ssh_path) def test_filemode_diff(self): """Testing parsing filemode changes Git diff""" diff = self._read_fixture("git_filemode.diff") file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, "testing") self.assertEqual(file.newFile, "testing") self.assertEqual(file.origInfo, "e69de29") self.assertEqual(file.newInfo, "bcae657") self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertEqual(file.data.splitlines()[0], "diff --git a/testing b/testing") self.assertEqual(file.data.splitlines()[-1], "+ADD") self.assertEqual(file.insert_count, 1) self.assertEqual(file.delete_count, 0) def test_filemode_with_following_diff(self): """Testing parsing filemode changes with following Git diff""" diff = self._read_fixture("git_filemode2.diff") file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, "testing") self.assertEqual(file.newFile, "testing") self.assertEqual(file.origInfo, "e69de29") self.assertEqual(file.newInfo, "bcae657") self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertEqual(file.data.splitlines()[0], "diff --git a/testing b/testing") self.assertEqual(file.data.splitlines()[-1], "+ADD") self.assertEqual(file.insert_count, 1) self.assertEqual(file.delete_count, 0) file = self._get_file_in_diff(diff, 1) self.assertEqual(file.origFile, "cfg/testcase.ini") self.assertEqual(file.newFile, "cfg/testcase.ini") self.assertEqual(file.origInfo, "cc18ec8") self.assertEqual(file.newInfo, "5e70b73") self.assertEqual(file.data.splitlines()[0], "diff --git a/cfg/testcase.ini b/cfg/testcase.ini") self.assertEqual(file.data.splitlines()[-1], "+db = pyunit") self.assertEqual(file.insert_count, 2) self.assertEqual(file.delete_count, 1) def test_simple_diff(self): """Testing parsing simple Git diff""" diff = self._read_fixture("git_simple.diff") file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, "cfg/testcase.ini") self.assertEqual(file.newFile, "cfg/testcase.ini") self.assertEqual(file.origInfo, "cc18ec8") self.assertEqual(file.newInfo, "5e70b73") self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertEqual(len(file.data), 249) self.assertEqual(file.data.splitlines()[0], "diff --git a/cfg/testcase.ini b/cfg/testcase.ini") self.assertEqual(file.data.splitlines()[-1], "+db = pyunit") self.assertEqual(file.insert_count, 2) self.assertEqual(file.delete_count, 1) def test_diff_with_unicode(self): """Testing parsing Git diff with unicode characters""" diff = ( "diff --git a/cfg/téstcase.ini b/cfg/téstcase.ini\n" "index cc18ec8..5e70b73 100644\n" "--- a/cfg/téstcase.ini\n" "+++ b/cfg/téstcase.ini\n" "@@ -1,6 +1,7 @@\n" "+blah blah blah\n" " [mysql]\n" " hóst = localhost\n" " pórt = 3306\n" " user = user\n" " pass = pass\n" "-db = pyunít\n" "+db = pyunít\n" ).encode("utf-8") file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, "cfg/téstcase.ini") self.assertEqual(file.newFile, "cfg/téstcase.ini") self.assertEqual(file.origInfo, "cc18ec8") self.assertEqual(file.newInfo, "5e70b73") self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertEqual(file.data.splitlines()[0].decode("utf-8"), "diff --git a/cfg/téstcase.ini b/cfg/téstcase.ini") self.assertEqual(file.data.splitlines()[-1].decode("utf-8"), "+db = pyunít") self.assertEqual(file.insert_count, 2) self.assertEqual(file.delete_count, 1) def test_diff_with_tabs_after_filename(self): """Testing parsing Git diffs with tabs after the filename""" diff = ( b"diff --git a/README b/README\n" b"index 712544e4343bf04967eb5ea80257f6c64d6f42c7.." b"f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n" b"--- a/README\t\n" b"+++ b/README\t\n" b"@ -1,1 +1,1 @@\n" b"-blah blah\n" b"+blah\n" b"-\n" b"1.7.1\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(files[0].origFile, "README") self.assertEqual(files[0].newFile, "README") self.assertEqual(files[0].origInfo, "712544e4343bf04967eb5ea80257f6c64d6f42c7") self.assertEqual(files[0].newInfo, "f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1") self.assertEqual(files[0].data, diff) self.assertEqual(files[0].insert_count, 1) self.assertEqual(files[0].delete_count, 2) def test_new_file_diff(self): """Testing parsing Git diff with new file""" diff = self._read_fixture("git_newfile.diff") file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, "IAMNEW") self.assertEqual(file.newFile, "IAMNEW") self.assertEqual(file.origInfo, PRE_CREATION) self.assertEqual(file.newInfo, "e69de29") self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertEqual(len(file.data), 123) self.assertEqual(file.data.splitlines()[0], "diff --git a/IAMNEW b/IAMNEW") self.assertEqual(file.data.splitlines()[-1], "+Hello") self.assertEqual(file.insert_count, 1) self.assertEqual(file.delete_count, 0) def test_new_file_no_content_diff(self): """Testing parsing Git diff new file, no content""" diff = self._read_fixture("git_newfile_nocontent.diff") files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, "newfile") self.assertEqual(file.newFile, "newfile") self.assertEqual(file.origInfo, PRE_CREATION) self.assertEqual(file.newInfo, "e69de29") self.assertFalse(file.binary) self.assertFalse(file.deleted) lines = file.data.splitlines() self.assertEqual(len(lines), 3) self.assertEqual(lines[0], "diff --git a/newfile b/newfile") self.assertEqual(file.insert_count, 0) self.assertEqual(file.delete_count, 0) def test_new_file_no_content_with_following_diff(self): """Testing parsing Git diff new file, no content, with following""" diff = self._read_fixture("git_newfile_nocontent2.diff") files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].origFile, "newfile") self.assertEqual(files[0].newFile, "newfile") self.assertEqual(files[0].origInfo, PRE_CREATION) self.assertEqual(files[0].newInfo, "e69de29") self.assertFalse(files[0].binary) self.assertFalse(files[0].deleted) lines = files[0].data.splitlines() self.assertEqual(len(lines), 3) self.assertEqual(lines[0], "diff --git a/newfile b/newfile") self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) self.assertEqual(files[1].origFile, "cfg/testcase.ini") self.assertEqual(files[1].newFile, "cfg/testcase.ini") self.assertEqual(files[1].origInfo, "cc18ec8") self.assertEqual(files[1].newInfo, "5e70b73") lines = files[1].data.splitlines() self.assertEqual(len(lines), 13) self.assertEqual(lines[0], "diff --git a/cfg/testcase.ini b/cfg/testcase.ini") self.assertEqual(lines[-1], "+db = pyunit") self.assertEqual(files[1].insert_count, 2) self.assertEqual(files[1].delete_count, 1) def test_del_file_diff(self): """Testing parsing Git diff with deleted file""" diff = self._read_fixture("git_delfile.diff") file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, "OLDFILE") self.assertEqual(file.newFile, "OLDFILE") self.assertEqual(file.origInfo, "8ebcb01") self.assertEqual(file.newInfo, "0000000") self.assertFalse(file.binary) self.assertTrue(file.deleted) self.assertEqual(len(file.data), 132) self.assertEqual(file.data.splitlines()[0], "diff --git a/OLDFILE b/OLDFILE") self.assertEqual(file.data.splitlines()[-1], "-Goodbye") self.assertEqual(file.insert_count, 0) self.assertEqual(file.delete_count, 1) def test_del_file_no_content_diff(self): """Testing parsing Git diff with deleted file, no content""" diff = ( b"diff --git a/empty b/empty\n" b"deleted file mode 100644\n" b"index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391.." b"0000000000000000000000000000000000000000\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].origFile, "empty") self.assertEqual(files[0].newFile, "empty") self.assertEqual(files[0].origInfo, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391") self.assertEqual(files[0].newInfo, "0000000000000000000000000000000000000000") self.assertFalse(files[0].binary) self.assertTrue(files[0].deleted) self.assertEqual(len(files[0].data), 141) self.assertEqual(files[0].data.splitlines()[0], "diff --git a/empty b/empty") self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) def test_del_file_no_content_with_following_diff(self): """Testing parsing Git diff with deleted file, no content, with following """ diff = ( b"diff --git a/empty b/empty\n" b"deleted file mode 100644\n" b"index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391.." b"0000000000000000000000000000000000000000\n" b"diff --git a/foo/bar b/foo/bar\n" b"index 484ba93ef5b0aed5b72af8f4e9dc4cfd10ef1a81.." b"0ae4095ddfe7387d405bd53bd59bbb5d861114c5 100644\n" b"--- a/foo/bar\n" b"+++ b/foo/bar\n" b"@@ -1 +1,2 @@\n" b"+Hello!\n" b"blah\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].origFile, "empty") self.assertEqual(files[0].newFile, "empty") self.assertEqual(files[0].origInfo, "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391") self.assertEqual(files[0].newInfo, "0000000000000000000000000000000000000000") self.assertFalse(files[0].binary) self.assertTrue(files[0].deleted) self.assertEqual(len(files[0].data), 141) self.assertEqual(files[0].data.splitlines()[0], "diff --git a/empty b/empty") self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) self.assertEqual(files[1].origFile, "foo/bar") self.assertEqual(files[1].newFile, "foo/bar") self.assertEqual(files[1].origInfo, "484ba93ef5b0aed5b72af8f4e9dc4cfd10ef1a81") self.assertEqual(files[1].newInfo, "0ae4095ddfe7387d405bd53bd59bbb5d861114c5") self.assertFalse(files[1].binary) self.assertFalse(files[1].deleted) lines = files[1].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], "diff --git a/foo/bar b/foo/bar") self.assertEqual(lines[5], "+Hello!") self.assertEqual(files[1].insert_count, 1) self.assertEqual(files[1].delete_count, 0) def test_binary_diff(self): """Testing parsing Git diff with binary""" diff = self._read_fixture("git_binary.diff") file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, "pysvn-1.5.1.tar.gz") self.assertEqual(file.newFile, "pysvn-1.5.1.tar.gz") self.assertEqual(file.origInfo, PRE_CREATION) self.assertEqual(file.newInfo, "86b520c") self.assertTrue(file.binary) self.assertFalse(file.deleted) lines = file.data.splitlines() self.assertEqual(len(lines), 4) self.assertEqual(lines[0], "diff --git a/pysvn-1.5.1.tar.gz b/pysvn-1.5.1.tar.gz") self.assertEqual(lines[3], "Binary files /dev/null and b/pysvn-1.5.1.tar.gz differ") self.assertEqual(file.insert_count, 0) self.assertEqual(file.delete_count, 0) def test_complex_diff(self): """Testing parsing Git diff with existing and new files""" diff = self._read_fixture("git_complex.diff") files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 7) self.assertEqual(files[0].origFile, "cfg/testcase.ini") self.assertEqual(files[0].newFile, "cfg/testcase.ini") self.assertEqual(files[0].origInfo, "5e35098") self.assertEqual(files[0].newInfo, "e254ef4") self.assertFalse(files[0].binary) self.assertFalse(files[0].deleted) self.assertEqual(files[0].insert_count, 2) self.assertEqual(files[0].delete_count, 1) self.assertEqual(len(files[0].data), 549) self.assertEqual(files[0].data.splitlines()[0], "diff --git a/cfg/testcase.ini b/cfg/testcase.ini") self.assertEqual(files[0].data.splitlines()[13], " if isinstance(value, basestring):") self.assertEqual(files[1].origFile, "tests/models.py") self.assertEqual(files[1].newFile, "tests/models.py") self.assertEqual(files[1].origInfo, PRE_CREATION) self.assertEqual(files[1].newInfo, "e69de29") self.assertFalse(files[1].binary) self.assertFalse(files[1].deleted) self.assertEqual(files[1].insert_count, 0) self.assertEqual(files[1].delete_count, 0) lines = files[1].data.splitlines() self.assertEqual(len(lines), 3) self.assertEqual(lines[0], "diff --git a/tests/models.py b/tests/models.py") self.assertEqual(files[2].origFile, "tests/tests.py") self.assertEqual(files[2].newFile, "tests/tests.py") self.assertEqual(files[2].origInfo, PRE_CREATION) self.assertEqual(files[2].newInfo, "e279a06") self.assertFalse(files[2].binary) self.assertFalse(files[2].deleted) self.assertEqual(files[2].insert_count, 2) self.assertEqual(files[2].delete_count, 0) lines = files[2].data.splitlines() self.assertEqual(len(lines), 8) self.assertEqual(lines[0], "diff --git a/tests/tests.py b/tests/tests.py") self.assertEqual(lines[7], "+This is some new content") self.assertEqual(files[3].origFile, "pysvn-1.5.1.tar.gz") self.assertEqual(files[3].newFile, "pysvn-1.5.1.tar.gz") self.assertEqual(files[3].origInfo, PRE_CREATION) self.assertEqual(files[3].newInfo, "86b520c") self.assertTrue(files[3].binary) self.assertFalse(files[3].deleted) self.assertEqual(files[3].insert_count, 0) self.assertEqual(files[3].delete_count, 0) lines = files[3].data.splitlines() self.assertEqual(len(lines), 4) self.assertEqual(lines[0], "diff --git a/pysvn-1.5.1.tar.gz b/pysvn-1.5.1.tar.gz") self.assertEqual(lines[3], "Binary files /dev/null and b/pysvn-1.5.1.tar.gz " "differ") self.assertEqual(files[4].origFile, "readme") self.assertEqual(files[4].newFile, "readme") self.assertEqual(files[4].origInfo, "5e35098") self.assertEqual(files[4].newInfo, "e254ef4") self.assertFalse(files[4].binary) self.assertFalse(files[4].deleted) self.assertEqual(files[4].insert_count, 1) self.assertEqual(files[4].delete_count, 1) lines = files[4].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], "diff --git a/readme b/readme") self.assertEqual(lines[6], "+Hello there") self.assertEqual(files[5].origFile, "OLDFILE") self.assertEqual(files[5].newFile, "OLDFILE") self.assertEqual(files[5].origInfo, "8ebcb01") self.assertEqual(files[5].newInfo, "0000000") self.assertFalse(files[5].binary) self.assertTrue(files[5].deleted) self.assertEqual(files[5].insert_count, 0) self.assertEqual(files[5].delete_count, 1) lines = files[5].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], "diff --git a/OLDFILE b/OLDFILE") self.assertEqual(lines[6], "-Goodbye") self.assertEqual(files[6].origFile, "readme2") self.assertEqual(files[6].newFile, "readme2") self.assertEqual(files[6].origInfo, "5e43098") self.assertEqual(files[6].newInfo, "e248ef4") self.assertFalse(files[6].binary) self.assertFalse(files[6].deleted) self.assertEqual(files[6].insert_count, 1) self.assertEqual(files[6].delete_count, 1) lines = files[6].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], "diff --git a/readme2 b/readme2") self.assertEqual(lines[6], "+Hello there") def test_parse_diff_with_index_range(self): """Testing Git diff parsing with an index range""" diff = ( b"diff --git a/foo/bar b/foo/bar2\n" b"similarity index 88%\n" b"rename from foo/bar\n" b"rename to foo/bar2\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n" b"--- a/foo/bar\n" b"+++ b/foo/bar2\n" b"@ -1,1 +1,1 @@\n" b"-blah blah\n" b"+blah\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].origFile, "foo/bar") self.assertEqual(files[0].newFile, "foo/bar2") self.assertEqual(files[0].origInfo, "612544e4343bf04967eb5ea80257f6c64d6f42c7") self.assertEqual(files[0].newInfo, "e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1") self.assertEqual(files[0].insert_count, 1) self.assertEqual(files[0].delete_count, 1) def test_parse_diff_with_deleted_binary_files(self): """Testing Git diff parsing with deleted binary files""" diff = ( b"diff --git a/foo.bin b/foo.bin\n" b"deleted file mode 100644\n" b"Binary file foo.bin has changed\n" b"diff --git a/bar.bin b/bar.bin\n" b"deleted file mode 100644\n" b"Binary file bar.bin has changed\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].origFile, "foo.bin") self.assertEqual(files[0].newFile, "foo.bin") self.assertEqual(files[0].binary, True) self.assertEqual(files[0].deleted, True) self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) self.assertEqual(files[1].origFile, "bar.bin") self.assertEqual(files[1].newFile, "bar.bin") self.assertEqual(files[1].binary, True) self.assertEqual(files[1].deleted, True) self.assertEqual(files[1].insert_count, 0) self.assertEqual(files[1].delete_count, 0) def test_parse_diff_with_all_headers(self): """Testing Git diff parsing and preserving all headers""" preamble = ( b"From 38d8fa94a9aa0c5b27943bec31d94e880165f1e0 Mon Sep " b"17 00:00:00 2001\n" b"From: Example Joe <*****@*****.**>\n" b"Date: Thu, 5 Apr 2012 00:41:12 -0700\n" b"Subject: [PATCH 1/1] Sample patch.\n" b"\n" b"This is a test summary.\n" b"\n" b"With a description.\n" b"---\n" b" foo/bar | 2 -+n" b" README | 2 -+n" b" 2 files changed, 2 insertions(+), 2 deletions(-)\n" b"\n" ) diff1 = ( b"diff --git a/foo/bar b/foo/bar2\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n" b"--- a/foo/bar\n" b"+++ b/foo/bar2\n" b"@ -1,1 +1,1 @@\n" b"-blah blah\n" b"+blah\n" ) diff2 = ( b"diff --git a/README b/README\n" b"index 712544e4343bf04967eb5ea80257f6c64d6f42c7.." b"f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n" b"--- a/README\n" b"+++ b/README\n" b"@ -1,1 +1,1 @@\n" b"-blah blah\n" b"+blah\n" b"-\n" b"1.7.1\n" ) diff = preamble + diff1 + diff2 files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].origFile, "foo/bar") self.assertEqual(files[0].newFile, "foo/bar2") self.assertEqual(files[0].origInfo, "612544e4343bf04967eb5ea80257f6c64d6f42c7") self.assertEqual(files[0].newInfo, "e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1") self.assertEqual(files[0].data, preamble + diff1) self.assertEqual(files[0].insert_count, 1) self.assertEqual(files[0].delete_count, 1) self.assertEqual(files[1].origFile, "README") self.assertEqual(files[1].newFile, "README") self.assertEqual(files[1].origInfo, "712544e4343bf04967eb5ea80257f6c64d6f42c7") self.assertEqual(files[1].newInfo, "f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1") self.assertEqual(files[1].data, diff2) self.assertEqual(files[1].insert_count, 1) self.assertEqual(files[1].delete_count, 2) def test_parse_diff_revision(self): """Testing Git revision number parsing""" self.assertEqual(self.tool.parse_diff_revision("doc/readme", "bf544ea"), ("doc/readme", "bf544ea")) self.assertEqual(self.tool.parse_diff_revision("/dev/null", "bf544ea"), ("/dev/null", PRE_CREATION)) self.assertEqual(self.tool.parse_diff_revision("/dev/null", "0000000"), ("/dev/null", PRE_CREATION)) def test_parse_diff_with_copy_and_rename_same_file(self): """Testing Git diff parsing with copy and rename of same file""" diff = ( b"diff --git a/foo/bar b/foo/bar2\n" b"similarity index 100%\n" b"copy from foo/bar\n" b"copy to foo/bar2\n" b"diff --git a/foo/bar b/foo/bar3\n" b"similarity index 92%\n" b"rename from foo/bar\n" b"rename to foo/bar3\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n" b"--- a/foo/bar\n" b"+++ b/foo/bar3\n" b"@@ -1,1 +1,1 @@\n" b"-blah blah\n" b"+blah\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) f = files[0] self.assertEqual(f.origFile, "foo/bar") self.assertEqual(f.newFile, "foo/bar2") self.assertEqual(f.origInfo, "") self.assertEqual(f.newInfo, "") self.assertEqual(f.insert_count, 0) self.assertEqual(f.delete_count, 0) self.assertFalse(f.moved) self.assertTrue(f.copied) f = files[1] self.assertEqual(f.origFile, "foo/bar") self.assertEqual(f.newFile, "foo/bar3") self.assertEqual(f.origInfo, "612544e4343bf04967eb5ea80257f6c64d6f42c7") self.assertEqual(f.newInfo, "e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1") self.assertEqual(f.insert_count, 1) self.assertEqual(f.delete_count, 1) self.assertTrue(f.moved) self.assertFalse(f.copied) def test_parse_diff_with_mode_change_and_rename(self): """Testing Git diff parsing with mode change and rename""" diff = ( b"diff --git a/foo/bar b/foo/bar2\n" b"old mode 100755\n" b"new mode 100644\n" b"similarity index 99%\n" b"rename from foo/bar\n" b"rename to foo/bar2\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1\n" b"--- a/foo/bar\n" b"+++ b/foo/bar2\n" b"@@ -1,1 +1,1 @@\n" b"-blah blah\n" b"+blah\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origFile, "foo/bar") self.assertEqual(f.newFile, "foo/bar2") self.assertEqual(f.origInfo, "612544e4343bf04967eb5ea80257f6c64d6f42c7") self.assertEqual(f.newInfo, "e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1") self.assertEqual(f.insert_count, 1) self.assertEqual(f.delete_count, 1) self.assertTrue(f.moved) self.assertFalse(f.copied) def test_diff_git_line_without_a_b(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes """ diff = ( b"diff --git foo foo\n" b"deleted file mode 100644\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"0000000000000000000000000000000000000000\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origFile, "foo") self.assertEqual(f.newFile, "foo") self.assertTrue(f.deleted) def test_diff_git_line_without_a_b_quotes(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with quotes """ diff = ( b'diff --git "foo" "foo"\n' b"deleted file mode 100644\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"0000000000000000000000000000000000000000\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origFile, "foo") self.assertEqual(f.newFile, "foo") self.assertTrue(f.deleted) def test_diff_git_line_without_a_b_and_spaces(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with spaces """ diff = ( b"diff --git foo bar1 foo bar1\n" b"deleted file mode 100644\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"0000000000000000000000000000000000000000\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origFile, "foo bar1") self.assertEqual(f.newFile, "foo bar1") self.assertTrue(f.deleted) def test_diff_git_line_without_a_b_and_spaces_quotes(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with space and quotes """ diff = ( b'diff --git "foo bar1" "foo bar1"\n' b"deleted file mode 100644\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"0000000000000000000000000000000000000000\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origFile, "foo bar1") self.assertEqual(f.newFile, "foo bar1") def test_diff_git_line_without_a_b_and_spaces_changed(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with spaces, with filename changes """ diff = ( b"diff --git foo bar1 foo bar2\n" b"deleted file mode 100644\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"0000000000000000000000000000000000000000\n" ) with self.assertRaises(DiffParserError) as cm: self.tool.get_parser(diff).parse() self.assertTrue(six.text_type(cm.exception).startswith('Unable to parse the "diff --git" line')) def test_diff_git_line_without_a_b_and_spaces_quotes_changed(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with spaces and quotes, with filename changes """ diff = ( b'diff --git "foo bar1" "foo bar2"\n' b"deleted file mode 100644\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"0000000000000000000000000000000000000000\n" b'diff --git "foo bar1" foo\n' b"deleted file mode 100644\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"0000000000000000000000000000000000000000\n" b'diff --git foo "foo bar1"\n' b"deleted file mode 100644\n" b"index 612544e4343bf04967eb5ea80257f6c64d6f42c7.." b"0000000000000000000000000000000000000000\n" ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 3) f = files[0] self.assertEqual(f.origFile, "foo bar1") self.assertEqual(f.newFile, "foo bar2") self.assertTrue(f.deleted) f = files[1] self.assertEqual(f.origFile, "foo bar1") self.assertEqual(f.newFile, "foo") f = files[2] self.assertEqual(f.origFile, "foo") self.assertEqual(f.newFile, "foo bar1") def test_file_exists(self): """Testing GitTool.file_exists""" self.assertTrue(self.tool.file_exists("readme", "e965047")) self.assertTrue(self.tool.file_exists("readme", "d6613f5")) self.assertTrue(not self.tool.file_exists("readme", PRE_CREATION)) self.assertTrue(not self.tool.file_exists("readme", "fffffff")) self.assertTrue(not self.tool.file_exists("readme2", "fffffff")) # these sha's are valid, but commit and tree objects, not blobs self.assertTrue(not self.tool.file_exists("readme", "a62df6c")) self.assertTrue(not self.tool.file_exists("readme2", "ccffbb4")) def test_get_file(self): """Testing GitTool.get_file""" self.assertEqual(self.tool.get_file("readme", PRE_CREATION), b"") self.assertTrue(isinstance(self.tool.get_file("readme", "e965047"), bytes)) self.assertEqual(self.tool.get_file("readme", "e965047"), b"Hello\n") self.assertEqual(self.tool.get_file("readme", "d6613f5"), b"Hello there\n") self.assertEqual(self.tool.get_file("readme"), b"Hello there\n") self.assertRaises(SCMError, lambda: self.tool.get_file("")) self.assertRaises(FileNotFoundError, lambda: self.tool.get_file("", "0000000")) self.assertRaises(FileNotFoundError, lambda: self.tool.get_file("hello", "0000000")) self.assertRaises(FileNotFoundError, lambda: self.tool.get_file("readme", "0000000")) def test_parse_diff_revision_with_remote_and_short_SHA1_error(self): """Testing GitTool.parse_diff_revision with remote files and short SHA1 error """ self.assertRaises(ShortSHA1Error, lambda: self.remote_tool.parse_diff_revision("README", "d7e96b3")) def test_get_file_with_remote_and_short_SHA1_error(self): """Testing GitTool.get_file with remote files and short SHA1 error""" self.assertRaises(ShortSHA1Error, lambda: self.remote_tool.get_file("README", "d7e96b3")) def test_valid_repository_https_username(self): """Testing GitClient.is_valid_repository with an HTTPS URL and external credentials """ client = GitClient("https://example.com/test.git", username="******", password="******") self.spy_on(client._run_git) client.is_valid_repository() self.assertEqual( client._run_git.calls[0].args[0], ["ls-remote", "https://*****:*****@example.com/test.git", "HEAD"] ) def test_raw_file_url_error(self): """Testing Repository.get_file re-fetches when raw file URL changes""" self.spy_on(self.remote_repository._get_file_uncached, call_fake=lambda a, b, x, y, z: "first") self.assertEqual(self.remote_repository.get_file("PATH", "d7e96b3"), "first") # Ensure output of fake result matches. self.remote_repository._get_file_uncached.unspy() self.spy_on(self.remote_repository._get_file_uncached, call_fake=lambda a, b, x, y, z: "second") # Grab from cache when no changes and change fake result to confirm # it is not called. self.assertEqual(self.remote_repository.get_file("PATH", "d7e96b3"), "first") self.remote_repository.raw_file_url = "http://github.com/api/v2/yaml/blob/show/reviewboard/<revision>" # When raw_file_url changed, do not grab from cache and ensure output # equals second fake value. self.assertEqual(self.remote_repository.get_file("PATH", "d7e96b3"), "second") def test_get_file_exists_caching_with_raw_url(self): """Testing Repository.get_file_exists properly checks file existence in repository or cache when raw file URL changes """ self.spy_on(self.remote_repository._get_file_exists_uncached, call_fake=lambda a, b, x, y, z: True) # Use spy to put key into cache self.assertTrue(self.remote_repository.get_file_exists("PATH", "d7e96b3")) # Remove spy to ensure key is still in cache without needing spy self.remote_repository._get_file_exists_uncached.unspy() self.assertTrue(self.remote_repository.get_file_exists("PATH", "d7e96b3")) self.remote_repository.raw_file_url = "http://github.com/api/v2/yaml/blob/show/reviewboard/<revision>" # Does not exist when raw_file_url changed because it is not cached. self.assertFalse(self.remote_repository.get_file_exists("PATH", "d7e96b3"))
class CommonSVNTestCase(SpyAgency, SCMTestCase): """Common unit tests for Subversion. This is meant to be subclassed for each backend that wants to run the common set of tests. """ backend = None backend_name = None fixtures = ['test_scmtools'] def setUp(self): super(CommonSVNTestCase, self).setUp() self._old_backend_setting = settings.SVNTOOL_BACKENDS settings.SVNTOOL_BACKENDS = [self.backend] recompute_svn_backend() self.svn_repo_path = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', 'testdata', 'svn_repo')) self.svn_ssh_path = ('svn+ssh://localhost%s' % self.svn_repo_path.replace('\\', '/')) self.repository = Repository(name='Subversion SVN', path='file://' + self.svn_repo_path, tool=Tool.objects.get(name='Subversion')) try: self.tool = self.repository.get_scmtool() except ImportError: raise nose.SkipTest('The %s backend could not be used. A ' 'dependency may be missing.' % self.backend) assert self.tool.client.__class__.__module__ == self.backend def tearDown(self): super(CommonSVNTestCase, self).tearDown() settings.SVNTOOL_BACKENDS = self._old_backend_setting recompute_svn_backend() def shortDescription(self): desc = super(CommonSVNTestCase, self).shortDescription() desc = desc.replace('<backend>', self.backend_name) return desc def test_ssh(self): """Testing SVN (<backend>) with a SSH-backed Subversion repository""" self._test_ssh(self.svn_ssh_path, 'trunk/doc/misc-docs/Makefile') def test_ssh_with_site(self): """Testing SVN (<backend>) with a SSH-backed Subversion repository with a LocalSite """ self._test_ssh_with_site(self.svn_ssh_path, 'trunk/doc/misc-docs/Makefile') def test_get_file(self): """Testing SVN (<backend>) get_file""" expected = (b'include ../tools/Makefile.base-vars\n' b'NAME = misc-docs\n' b'OUTNAME = svn-misc-docs\n' b'INSTALL_DIR = $(DESTDIR)/usr/share/doc/subversion\n' b'include ../tools/Makefile.base-rules\n') # There are 3 versions of this test in order to get 100% coverage of # the svn module. rev = Revision('2') file = 'trunk/doc/misc-docs/Makefile' value = self.tool.get_file(file, rev) self.assertTrue(isinstance(value, bytes)) self.assertEqual(value, expected) self.assertEqual(self.tool.get_file('/' + file, rev), expected) self.assertEqual( self.tool.get_file(self.repository.path + '/' + file, rev), expected) self.assertTrue(self.tool.file_exists('trunk/doc/misc-docs/Makefile')) self.assertTrue( not self.tool.file_exists('trunk/doc/misc-docs/Makefile2')) self.assertRaises(FileNotFoundError, lambda: self.tool.get_file('')) self.assertRaises(FileNotFoundError, lambda: self.tool.get_file('hello', PRE_CREATION)) def test_revision_parsing(self): """Testing SVN (<backend>) revision number parsing""" self.assertEqual( self.tool.parse_diff_revision('', '(working copy)')[1], HEAD) self.assertEqual( self.tool.parse_diff_revision('', ' (revision 0)')[1], PRE_CREATION) self.assertEqual(self.tool.parse_diff_revision('', '(revision 1)')[1], '1') self.assertEqual(self.tool.parse_diff_revision('', '(revision 23)')[1], '23') # Fix for bug 2176 self.assertEqual( self.tool.parse_diff_revision('', '\t(revision 4)')[1], '4') self.assertEqual( self.tool.parse_diff_revision( '', '2007-06-06 15:32:23 UTC (rev 10958)')[1], '10958') # Fix for bug 2632 self.assertEqual(self.tool.parse_diff_revision('', '(revision )')[1], PRE_CREATION) self.assertRaises(SCMError, lambda: self.tool.parse_diff_revision('', 'hello')) # Verify that 'svn diff' localized revision strings parse correctly. self.assertEqual(self.tool.parse_diff_revision('', '(revisión: 5)')[1], '5') self.assertEqual(self.tool.parse_diff_revision('', '(リビジョン 6)')[1], '6') self.assertEqual(self.tool.parse_diff_revision('', '(版本 7)')[1], '7') def test_revision_parsing_with_nonexistent(self): """Testing SVN (<backend>) revision parsing with "(nonexistent)" revision indicator """ # English self.assertEqual( self.tool.parse_diff_revision('', '(nonexistent)')[1], PRE_CREATION) # German self.assertEqual( self.tool.parse_diff_revision('', '(nicht existent)')[1], PRE_CREATION) # Simplified Chinese self.assertEqual( self.tool.parse_diff_revision('', '(不存在的)')[1], PRE_CREATION) def test_revision_parsing_with_nonexistent_and_branches(self): """Testing SVN (<backend>) revision parsing with relocation information and nonexisitent revision specifier. """ self.assertEqual( self.tool.parse_diff_revision( '', '(.../trunk) (nonexistent)')[1], PRE_CREATION) self.assertEqual( self.tool.parse_diff_revision( '', '(.../branches/branch-1.0) (nicht existent)')[1], PRE_CREATION) self.assertEqual( self.tool.parse_diff_revision( '', ' (.../trunk) (不存在的)')[1], PRE_CREATION) def test_interface(self): """Testing SVN (<backend>) with basic SVNTool API""" self.assertFalse(self.tool.diffs_use_absolute_paths) self.assertRaises(NotImplementedError, lambda: self.tool.get_changeset(1)) def test_binary_diff(self): """Testing SVN (<backend>) parsing SVN diff with binary file""" diff = (b'Index: binfile\n' b'============================================================' b'=======\n' b'Cannot display: file marked as a binary type.\n' b'svn:mime-type = application/octet-stream\n') file = self.tool.get_parser(diff).parse()[0] self.assertEqual(file.origFile, 'binfile') self.assertEqual(file.binary, True) def test_keyword_diff(self): """Testing SVN (<backend>) parsing diff with keywords""" # 'svn cat' will expand special variables in svn:keywords, # but 'svn diff' doesn't expand anything. This causes the # patch to fail if those variables appear in the patch context. diff = (b'Index: Makefile\n' b'===========================================================' b'========\n' b'--- Makefile (revision 4)\n' b'+++ Makefile (working copy)\n' b'@@ -1,6 +1,7 @@\n' b' # $Id$\n' b' # $Rev$\n' b' # $Revision:: $\n' b'+# foo\n' b' include ../tools/Makefile.base-vars\n' b' NAME = misc-docs\n' b' OUTNAME = svn-misc-docs\n') filename = 'trunk/doc/misc-docs/Makefile' rev = Revision('4') file = self.tool.get_file(filename, rev) patch(diff, file, filename) def test_unterminated_keyword_diff(self): """Testing SVN (<backend>) parsing diff with unterminated keywords""" diff = (b'Index: Makefile\n' b'===========================================================' b'========\n' b'--- Makefile (revision 4)\n' b'+++ Makefile (working copy)\n' b'@@ -1,6 +1,7 @@\n' b' # $Id$\n' b' # $Id:\n' b' # $Rev$\n' b' # $Revision:: $\n' b'+# foo\n' b' include ../tools/Makefile.base-vars\n' b' NAME = misc-docs\n' b' OUTNAME = svn-misc-docs\n') filename = 'trunk/doc/misc-docs/Makefile' rev = Revision('5') file = self.tool.get_file(filename, rev) patch(diff, file, filename) def test_svn16_property_diff(self): """Testing SVN (<backend>) parsing SVN 1.6 diff with property changes """ prop_diff = ( b'Index:\n' b'======================================================' b'=============\n' b'--- (revision 123)\n' b'+++ (working copy)\n' b'Property changes on: .\n' b'______________________________________________________' b'_____________\n' b'Modified: reviewboard:url\n' b'## -1 +1 ##\n' b'-http://reviews.reviewboard.org\n' b'+http://reviews.reviewboard.org\n') bin_diff = ( b'Index: binfile\n' b'=======================================================' b'============\nCannot display: file marked as a ' b'binary type.\nsvn:mime-type = application/octet-stream\n') diff = prop_diff + bin_diff files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].origFile, 'binfile') self.assertTrue(files[0].binary) self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) def test_svn17_property_diff(self): """Testing SVN (<backend>) parsing SVN 1.7+ diff with property changes """ prop_diff = ( b'Index .:\n' b'======================================================' b'=============\n' b'--- . (revision 123)\n' b'+++ . (working copy)\n' b'\n' b'Property changes on: .\n' b'______________________________________________________' b'_____________\n' b'Modified: reviewboard:url\n' b'## -0,0 +1,3 ##\n' b'-http://reviews.reviewboard.org\n' b'+http://reviews.reviewboard.org\n' b'Added: myprop\n' b'## -0,0 +1 ##\n' b'+Property test.\n') bin_diff = ( b'Index: binfile\n' b'=======================================================' b'============\nCannot display: file marked as a ' b'binary type.\nsvn:mime-type = application/octet-stream\n') diff = prop_diff + bin_diff files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].origFile, 'binfile') self.assertTrue(files[0].binary) self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) def test_unicode_diff(self): """Testing SVN (<backend>) parsing diff with unicode characters""" diff = ('Index: Filé\n' '===========================================================' '========\n' '--- Filé (revision 4)\n' '+++ Filé (working copy)\n' '@@ -1,6 +1,7 @@\n' '+# foó\n' ' include ../tools/Makefile.base-vars\n' ' NAME = misc-docs\n' ' OUTNAME = svn-misc-docs\n').encode('utf-8') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].origFile, 'Filé') self.assertFalse(files[0].binary) self.assertEqual(files[0].insert_count, 1) self.assertEqual(files[0].delete_count, 0) def test_diff_with_spaces_in_filenames(self): """Testing SVN (<backend>) parsing diff with spaces in filenames""" diff = (b'Index: File with spaces\n' b'===========================================================' b'========\n' b'--- File with spaces (revision 4)\n' b'+++ File with spaces (working copy)\n' b'@@ -1,6 +1,7 @@\n' b'+# foo\n' b' include ../tools/Makefile.base-vars\n' b' NAME = misc-docs\n' b' OUTNAME = svn-misc-docs\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].origFile, 'File with spaces') self.assertFalse(files[0].binary) self.assertEqual(files[0].insert_count, 1) self.assertEqual(files[0].delete_count, 0) def test_diff_with_added_empty_file(self): """Testing parsing SVN diff with added empty file""" diff = (b'Index: empty-file\t(added)\n' b'===========================================================' b'========\n' b'--- empty-file\t(revision 0)\n' b'+++ empty-file\t(revision 0)\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].origFile, 'empty-file') self.assertEqual(files[0].newFile, 'empty-file') self.assertEqual(files[0].origInfo, '(revision 0)') self.assertEqual(files[0].newInfo, '(revision 0)') self.assertFalse(files[0].binary) self.assertFalse(files[0].deleted) self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) def test_diff_with_deleted_empty_file(self): """Testing parsing SVN diff with deleted empty file""" diff = (b'Index: empty-file\t(deleted)\n' b'===========================================================' b'========\n' b'--- empty-file\t(revision 4)\n' b'+++ empty-file\t(working copy)\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].origFile, 'empty-file') self.assertEqual(files[0].newFile, 'empty-file') self.assertEqual(files[0].origInfo, '(revision 4)') self.assertEqual(files[0].newInfo, '(working copy)') self.assertFalse(files[0].binary) self.assertTrue(files[0].deleted) self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) def test_get_branches(self): """Testing SVN (<backend>) get_branches""" branches = self.tool.get_branches() self.assertEqual(len(branches), 3) self.assertEqual(branches[0], Branch(id='trunk', name='trunk', commit='9', default=True)) self.assertEqual(branches[1], Branch(id='branches/branch1', name='branch1', commit='7', default=False)) self.assertEqual(branches[2], Branch(id='top-level-branch', name='top-level-branch', commit='10', default=False)) def test_get_commits(self): """Testing SVN (<backend>) get_commits""" commits = self.tool.get_commits(start='5') self.assertEqual(len(commits), 5) self.assertEqual( commits[0], Commit('chipx86', '5', '2010-05-21T09:33:40.893946', 'Add an unterminated keyword for testing bug #1523\n', '4')) commits = self.tool.get_commits(start='7') self.assertEqual(len(commits), 7) self.assertEqual( commits[1], Commit('david', '6', '2013-06-13T07:43:04.725088', 'Add a branches directory', '5')) def test_get_commits_with_branch(self): """Testing SVN (<backend>) get_commits with branch""" commits = self.tool.get_commits(branch='/branches/branch1', start='5') self.assertEqual(len(commits), 5) self.assertEqual( commits[0], Commit('chipx86', '5', '2010-05-21T09:33:40.893946', 'Add an unterminated keyword for testing bug #1523\n', '4')) commits = self.tool.get_commits(branch='/branches/branch1', start='7') self.assertEqual(len(commits), 6) self.assertEqual( commits[0], Commit('david', '7', '2013-06-13T07:43:27.259554', 'Add a branch', '5')) self.assertEqual( commits[1], Commit('chipx86', '5', '2010-05-21T09:33:40.893946', 'Add an unterminated keyword for testing bug #1523\n', '4')) def test_get_commits_with_no_date(self): """Testing SVN (<backend>) get_commits with no date in commit""" def _get_log(*args, **kwargs): return [ { 'author': 'chipx86', 'revision': '5', 'message': 'Commit 1', }, ] self.spy_on(self.tool.client.get_log, _get_log) commits = self.tool.get_commits(start='5') self.assertEqual(len(commits), 1) self.assertEqual( commits[0], Commit('chipx86', '5', '', 'Commit 1')) def test_get_change(self): """Testing SVN (<backend>) get_change""" commit = self.tool.get_change('5') self.assertEqual(md5(commit.message.encode('utf-8')).hexdigest(), '928336c082dd756e3f7af4cde4724ebf') self.assertEqual(md5(commit.diff.encode('utf-8')).hexdigest(), '56e50374056931c03a333f234fa63375') def test_utf8_keywords(self): """Testing SVN (<backend>) with UTF-8 files with keywords""" self.repository.get_file('trunk/utf8-file.txt', '9')
class GitTests(SpyAgency, SCMTestCase): """Unit tests for Git.""" fixtures = ['test_scmtools'] def setUp(self): super(GitTests, self).setUp() tool = Tool.objects.get(name='Git') self.local_repo_path = os.path.join(os.path.dirname(__file__), '..', 'testdata', 'git_repo') self.git_ssh_path = ('localhost:%s' % self.local_repo_path.replace('\\', '/')) remote_repo_path = '[email protected]:reviewboard/reviewboard.git' remote_repo_raw_url = ('http://github.com/api/v2/yaml/blob/show/' 'reviewboard/reviewboard/<revision>') self.repository = Repository(name='Git test repo', path=self.local_repo_path, tool=tool) self.remote_repository = Repository(name='Remote Git test repo', path=remote_repo_path, raw_file_url=remote_repo_raw_url, tool=tool) try: self.tool = self.repository.get_scmtool() self.remote_tool = self.remote_repository.get_scmtool() except ImportError: raise nose.SkipTest('git binary not found') def _read_fixture(self, filename): filename = os.path.join(os.path.dirname(__file__), '..', 'testdata', filename) with open(filename, 'rb') as f: return f.read() def _get_file_in_diff(self, diff, filenum=0): files = self.tool.get_parser(diff).parse() self.assertTrue(filenum < len(files)) return files[filenum] def test_ssh(self): """Testing a SSH-backed git repository""" self._test_ssh(self.git_ssh_path) def test_ssh_with_site(self): """Testing a SSH-backed git repository with a LocalSite""" self._test_ssh_with_site(self.git_ssh_path) def test_filemode_diff(self): """Testing parsing filemode changes Git diff""" diff = (b'diff --git a/testing b/testing\n' b'old mode 100755\n' b'new mode 100644\n' b'index e69de29..bcae657\n' b'--- a/testing\n' b'+++ b/testing\n' b'@@ -0,0 +1 @@\n' b'+ADD\n' b'diff --git a/testing2 b/testing2\n' b'old mode 100644\n' b'new mode 100755\n') file = self._get_file_in_diff(diff) self.assertEqual(file.orig_filename, b'testing') self.assertEqual(file.modified_filename, b'testing') self.assertEqual(file.orig_file_details, b'e69de29') self.assertEqual(file.modified_file_details, b'bcae657') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(file.data.splitlines()[0], b'diff --git a/testing b/testing') self.assertEqual(file.data.splitlines()[-1], b'+ADD') self.assertEqual(file.insert_count, 1) self.assertEqual(file.delete_count, 0) def test_filemode_with_following_diff(self): """Testing parsing filemode changes with following Git diff""" diff = (b'diff --git a/testing b/testing\n' b'old mode 100755\n' b'new mode 100644\n' b'index e69de29..bcae657\n' b'--- a/testing\n' b'+++ b/testing\n' b'@@ -0,0 +1 @@\n' b'+ADD\n' b'diff --git a/testing2 b/testing2\n' b'old mode 100644\n' b'new mode 100755\n' b'diff --git a/cfg/testcase.ini b/cfg/testcase.ini\n' b'index cc18ec8..5e70b73 100644\n' b'--- a/cfg/testcase.ini\n' b'+++ b/cfg/testcase.ini\n' b'@@ -1,6 +1,7 @@\n' b'+blah blah blah\n' b' [mysql]\n' b' host = localhost\n' b' port = 3306\n' b' user = user\n' b' pass = pass\n' b'-db = pyunit\n' b'+db = pyunit\n') file = self._get_file_in_diff(diff) self.assertEqual(file.orig_filename, b'testing') self.assertEqual(file.modified_filename, b'testing') self.assertEqual(file.orig_file_details, b'e69de29') self.assertEqual(file.modified_file_details, b'bcae657') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(file.data.splitlines()[0], b'diff --git a/testing b/testing') self.assertEqual(file.data.splitlines()[-1], b'+ADD') self.assertEqual(file.insert_count, 1) self.assertEqual(file.delete_count, 0) file = self._get_file_in_diff(diff, 1) self.assertEqual(file.orig_filename, b'cfg/testcase.ini') self.assertEqual(file.modified_filename, b'cfg/testcase.ini') self.assertEqual(file.orig_file_details, b'cc18ec8') self.assertEqual(file.modified_file_details, b'5e70b73') self.assertEqual(file.data.splitlines()[0], b'diff --git a/cfg/testcase.ini b/cfg/testcase.ini') self.assertEqual(file.data.splitlines()[-1], b'+db = pyunit') self.assertEqual(file.insert_count, 2) self.assertEqual(file.delete_count, 1) def test_simple_diff(self): """Testing parsing simple Git diff""" diff = (b'diff --git a/cfg/testcase.ini b/cfg/testcase.ini\n' b'index cc18ec8..5e70b73 100644\n' b'--- a/cfg/testcase.ini\n' b'+++ b/cfg/testcase.ini\n' b'@@ -1,6 +1,7 @@\n' b'+blah blah blah\n' b' [mysql]\n' b' host = localhost\n' b' port = 3306\n' b' user = user\n' b' pass = pass\n' b'-db = pyunit\n' b'+db = pyunit\n') file = self._get_file_in_diff(diff) self.assertEqual(file.orig_filename, b'cfg/testcase.ini') self.assertEqual(file.modified_filename, b'cfg/testcase.ini') self.assertEqual(file.orig_file_details, b'cc18ec8') self.assertEqual(file.modified_file_details, b'5e70b73') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(len(file.data), 249) self.assertEqual(file.data.splitlines()[0], b'diff --git a/cfg/testcase.ini b/cfg/testcase.ini') self.assertEqual(file.data.splitlines()[-1], b'+db = pyunit') self.assertEqual(file.insert_count, 2) self.assertEqual(file.delete_count, 1) def test_diff_with_unicode(self): """Testing parsing Git diff with unicode characters""" diff = ('diff --git a/cfg/téstcase.ini b/cfg/téstcase.ini\n' 'index cc18ec8..5e70b73 100644\n' '--- a/cfg/téstcase.ini\n' '+++ b/cfg/téstcase.ini\n' '@@ -1,6 +1,7 @@\n' '+blah blah blah\n' ' [mysql]\n' ' hóst = localhost\n' ' pórt = 3306\n' ' user = user\n' ' pass = pass\n' '-db = pyunít\n' '+db = pyunít\n').encode('utf-8') file = self._get_file_in_diff(diff) self.assertEqual(file.orig_filename, 'cfg/téstcase.ini'.encode('utf-8')) self.assertEqual(file.modified_filename, 'cfg/téstcase.ini'.encode('utf-8')) self.assertEqual(file.orig_file_details, b'cc18ec8') self.assertEqual(file.modified_file_details, b'5e70b73') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(file.data.splitlines()[0].decode('utf-8'), 'diff --git a/cfg/téstcase.ini b/cfg/téstcase.ini') self.assertEqual(file.data.splitlines()[-1], '+db = pyunít'.encode('utf-8')) self.assertEqual(file.insert_count, 2) self.assertEqual(file.delete_count, 1) def test_diff_with_tabs_after_filename(self): """Testing parsing Git diffs with tabs after the filename""" diff = (b'diff --git a/README b/README\n' b'index 712544e4343bf04967eb5ea80257f6c64d6f42c7..' b'f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n' b'--- a/README\t\n' b'+++ b/README\t\n' b'@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n' b'-\n' b'1.7.1\n') files = self.tool.get_parser(diff).parse() self.assertEqual(files[0].orig_filename, b'README') self.assertEqual(files[0].modified_filename, b'README') self.assertEqual(files[0].orig_file_details, b'712544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(files[0].modified_file_details, b'f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(files[0].data, diff) self.assertEqual(files[0].insert_count, 1) self.assertEqual(files[0].delete_count, 2) def test_new_file_diff(self): """Testing parsing Git diff with new file""" diff = (b'diff --git a/IAMNEW b/IAMNEW\n' b'new file mode 100644\n' b'index 0000000..e69de29\n' b'--- /dev/null\n' b'+++ b/IAMNEW\n' b'@@ -0,0 +1,1 @@\n' b'+Hello\n') file = self._get_file_in_diff(diff) self.assertEqual(file.orig_filename, b'IAMNEW') self.assertEqual(file.modified_filename, b'IAMNEW') self.assertEqual(file.orig_file_details, PRE_CREATION) self.assertEqual(file.modified_file_details, b'e69de29') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(len(file.data), 123) self.assertEqual(file.data.splitlines()[0], b'diff --git a/IAMNEW b/IAMNEW') self.assertEqual(file.data.splitlines()[-1], b'+Hello') self.assertEqual(file.insert_count, 1) self.assertEqual(file.delete_count, 0) def test_new_file_no_content_diff(self): """Testing parsing Git diff new file, no content""" diff = (b'diff --git a/newfile b/newfile\n' b'new file mode 100644\n' b'index 0000000..e69de29\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) file = self._get_file_in_diff(diff) self.assertEqual(file.orig_filename, b'newfile') self.assertEqual(file.modified_filename, b'newfile') self.assertEqual(file.orig_file_details, PRE_CREATION) self.assertEqual(file.modified_file_details, b'e69de29') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) lines = file.data.splitlines() self.assertEqual(len(lines), 3) self.assertEqual(lines[0], b'diff --git a/newfile b/newfile') self.assertEqual(file.insert_count, 0) self.assertEqual(file.delete_count, 0) def test_new_file_no_content_with_following_diff(self): """Testing parsing Git diff new file, no content, with following""" diff = (b'diff --git a/newfile b/newfile\n' b'new file mode 100644\n' b'index 0000000..e69de29\n' b'diff --git a/cfg/testcase.ini b/cfg/testcase.ini\n' b'index cc18ec8..5e70b73 100644\n' b'--- a/cfg/testcase.ini\n' b'+++ b/cfg/testcase.ini\n' b'@@ -1,6 +1,7 @@\n' b'+blah blah blah\n' b' [mysql]\n' b' host = localhost\n' b' port = 3306\n' b' user = user\n' b' pass = pass\n' b'-db = pyunit\n' b'+db = pyunit\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].orig_filename, b'newfile') self.assertEqual(files[0].modified_filename, b'newfile') self.assertEqual(files[0].orig_file_details, PRE_CREATION) self.assertEqual(files[0].modified_file_details, b'e69de29') self.assertFalse(files[0].binary) self.assertFalse(files[0].deleted) self.assertFalse(files[0].is_symlink) lines = files[0].data.splitlines() self.assertEqual(len(lines), 3) self.assertEqual(lines[0], b'diff --git a/newfile b/newfile') self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) self.assertEqual(files[1].orig_filename, b'cfg/testcase.ini') self.assertEqual(files[1].modified_filename, b'cfg/testcase.ini') self.assertEqual(files[1].orig_file_details, b'cc18ec8') self.assertEqual(files[1].modified_file_details, b'5e70b73') lines = files[1].data.splitlines() self.assertEqual(len(lines), 13) self.assertEqual(lines[0], b'diff --git a/cfg/testcase.ini b/cfg/testcase.ini') self.assertEqual(lines[-1], b'+db = pyunit') self.assertEqual(files[1].insert_count, 2) self.assertEqual(files[1].delete_count, 1) def test_del_file_diff(self): """Testing parsing Git diff with deleted file""" diff = (b'diff --git a/OLDFILE b/OLDFILE\n' b'deleted file mode 100644\n' b'index 8ebcb01..0000000\n' b'--- a/OLDFILE\n' b'+++ /dev/null\n' b'@@ -1,1 +0,0 @@\n' b'-Goodbye\n') file = self._get_file_in_diff(diff) self.assertEqual(file.orig_filename, b'OLDFILE') self.assertEqual(file.modified_filename, b'OLDFILE') self.assertEqual(file.orig_file_details, b'8ebcb01') self.assertEqual(file.modified_file_details, b'0000000') self.assertFalse(file.binary) self.assertTrue(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(len(file.data), 132) self.assertEqual(file.data.splitlines()[0], b'diff --git a/OLDFILE b/OLDFILE') self.assertEqual(file.data.splitlines()[-1], b'-Goodbye') self.assertEqual(file.insert_count, 0) self.assertEqual(file.delete_count, 1) def test_del_file_no_content_diff(self): """Testing parsing Git diff with deleted file, no content""" diff = (b'diff --git a/empty b/empty\n' b'deleted file mode 100644\n' b'index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].orig_filename, b'empty') self.assertEqual(files[0].modified_filename, b'empty') self.assertEqual(files[0].orig_file_details, b'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391') self.assertEqual(files[0].modified_file_details, b'0000000000000000000000000000000000000000') self.assertFalse(files[0].binary) self.assertTrue(files[0].deleted) self.assertFalse(files[0].is_symlink) self.assertEqual(len(files[0].data), 141) self.assertEqual(files[0].data.splitlines()[0], b'diff --git a/empty b/empty') self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) def test_del_file_no_content_with_following_diff(self): """Testing parsing Git diff with deleted file, no content, with following """ diff = (b'diff --git a/empty b/empty\n' b'deleted file mode 100644\n' b'index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..' b'0000000000000000000000000000000000000000\n' b'diff --git a/foo/bar b/foo/bar\n' b'index 484ba93ef5b0aed5b72af8f4e9dc4cfd10ef1a81..' b'0ae4095ddfe7387d405bd53bd59bbb5d861114c5 100644\n' b'--- a/foo/bar\n' b'+++ b/foo/bar\n' b'@@ -1 +1,2 @@\n' b'+Hello!\n' b'blah\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].orig_filename, b'empty') self.assertEqual(files[0].modified_filename, b'empty') self.assertEqual(files[0].orig_file_details, b'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391') self.assertEqual(files[0].modified_file_details, b'0000000000000000000000000000000000000000') self.assertFalse(files[0].binary) self.assertTrue(files[0].deleted) self.assertFalse(files[0].is_symlink) self.assertEqual(len(files[0].data), 141) self.assertEqual(files[0].data.splitlines()[0], b'diff --git a/empty b/empty') self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) self.assertEqual(files[1].orig_filename, b'foo/bar') self.assertEqual(files[1].modified_filename, b'foo/bar') self.assertEqual(files[1].orig_file_details, b'484ba93ef5b0aed5b72af8f4e9dc4cfd10ef1a81') self.assertEqual(files[1].modified_file_details, b'0ae4095ddfe7387d405bd53bd59bbb5d861114c5') self.assertFalse(files[1].binary) self.assertFalse(files[1].deleted) self.assertFalse(files[1].is_symlink) lines = files[1].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], b'diff --git a/foo/bar b/foo/bar') self.assertEqual(lines[5], b'+Hello!') self.assertEqual(files[1].insert_count, 1) self.assertEqual(files[1].delete_count, 0) def test_binary_diff(self): """Testing parsing Git diff with binary""" diff = (b'diff --git a/pysvn-1.5.1.tar.gz b/pysvn-1.5.1.tar.gz\n' b'new file mode 100644\n' b'index 0000000..86b520c\n' b'Binary files /dev/null and b/pysvn-1.5.1.tar.gz differ\n') file = self._get_file_in_diff(diff) self.assertEqual(file.orig_filename, b'pysvn-1.5.1.tar.gz') self.assertEqual(file.modified_filename, b'pysvn-1.5.1.tar.gz') self.assertEqual(file.orig_file_details, PRE_CREATION) self.assertEqual(file.modified_file_details, b'86b520c') self.assertTrue(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) lines = file.data.splitlines() self.assertEqual(len(lines), 4) self.assertEqual( lines[0], b'diff --git a/pysvn-1.5.1.tar.gz b/pysvn-1.5.1.tar.gz') self.assertEqual( lines[3], b'Binary files /dev/null and b/pysvn-1.5.1.tar.gz differ') self.assertEqual(file.insert_count, 0) self.assertEqual(file.delete_count, 0) def test_complex_diff(self): """Testing parsing Git diff with existing and new files""" diff = self._read_fixture('git_complex.diff') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 7) self.assertEqual(files[0].orig_filename, b'cfg/testcase.ini') self.assertEqual(files[0].modified_filename, b'cfg/testcase.ini') self.assertEqual(files[0].orig_file_details, b'5e35098') self.assertEqual(files[0].modified_file_details, b'e254ef4') self.assertFalse(files[0].binary) self.assertFalse(files[0].deleted) self.assertFalse(files[0].is_symlink) self.assertEqual(files[0].insert_count, 2) self.assertEqual(files[0].delete_count, 1) self.assertEqual(len(files[0].data), 549) self.assertEqual(files[0].data.splitlines()[0], b'diff --git a/cfg/testcase.ini b/cfg/testcase.ini') self.assertEqual(files[0].data.splitlines()[13], b' if isinstance(value, basestring):') self.assertEqual(files[1].orig_filename, b'tests/models.py') self.assertEqual(files[1].modified_filename, b'tests/models.py') self.assertEqual(files[1].orig_file_details, PRE_CREATION) self.assertEqual(files[1].modified_file_details, b'e69de29') self.assertFalse(files[1].binary) self.assertFalse(files[1].deleted) self.assertFalse(files[1].is_symlink) self.assertEqual(files[1].insert_count, 0) self.assertEqual(files[1].delete_count, 0) lines = files[1].data.splitlines() self.assertEqual(len(lines), 3) self.assertEqual(lines[0], b'diff --git a/tests/models.py b/tests/models.py') self.assertEqual(files[2].orig_filename, b'tests/tests.py') self.assertEqual(files[2].modified_filename, b'tests/tests.py') self.assertEqual(files[2].orig_file_details, PRE_CREATION) self.assertEqual(files[2].modified_file_details, b'e279a06') self.assertFalse(files[2].binary) self.assertFalse(files[2].deleted) self.assertFalse(files[2].is_symlink) self.assertEqual(files[2].insert_count, 2) self.assertEqual(files[2].delete_count, 0) lines = files[2].data.splitlines() self.assertEqual(len(lines), 8) self.assertEqual(lines[0], b'diff --git a/tests/tests.py b/tests/tests.py') self.assertEqual(lines[7], b'+This is some new content') self.assertEqual(files[3].orig_filename, b'pysvn-1.5.1.tar.gz') self.assertEqual(files[3].modified_filename, b'pysvn-1.5.1.tar.gz') self.assertEqual(files[3].orig_file_details, PRE_CREATION) self.assertEqual(files[3].modified_file_details, b'86b520c') self.assertTrue(files[3].binary) self.assertFalse(files[3].deleted) self.assertFalse(files[3].is_symlink) self.assertEqual(files[3].insert_count, 0) self.assertEqual(files[3].delete_count, 0) lines = files[3].data.splitlines() self.assertEqual(len(lines), 4) self.assertEqual( lines[0], b'diff --git a/pysvn-1.5.1.tar.gz b/pysvn-1.5.1.tar.gz') self.assertEqual( lines[3], b'Binary files /dev/null and b/pysvn-1.5.1.tar.gz ' b'differ') self.assertEqual(files[4].orig_filename, b'readme') self.assertEqual(files[4].modified_filename, b'readme') self.assertEqual(files[4].orig_file_details, b'5e35098') self.assertEqual(files[4].modified_file_details, b'e254ef4') self.assertFalse(files[4].binary) self.assertFalse(files[4].deleted) self.assertFalse(files[4].is_symlink) self.assertEqual(files[4].insert_count, 1) self.assertEqual(files[4].delete_count, 1) lines = files[4].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], b'diff --git a/readme b/readme') self.assertEqual(lines[6], b'+Hello there') self.assertEqual(files[5].orig_filename, b'OLDFILE') self.assertEqual(files[5].modified_filename, b'OLDFILE') self.assertEqual(files[5].orig_file_details, b'8ebcb01') self.assertEqual(files[5].modified_file_details, b'0000000') self.assertFalse(files[5].binary) self.assertTrue(files[5].deleted) self.assertFalse(files[5].is_symlink) self.assertEqual(files[5].insert_count, 0) self.assertEqual(files[5].delete_count, 1) lines = files[5].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], b'diff --git a/OLDFILE b/OLDFILE') self.assertEqual(lines[6], b'-Goodbye') self.assertEqual(files[6].orig_filename, b'readme2') self.assertEqual(files[6].modified_filename, b'readme2') self.assertEqual(files[6].orig_file_details, b'5e43098') self.assertEqual(files[6].modified_file_details, b'e248ef4') self.assertFalse(files[6].binary) self.assertFalse(files[6].deleted) self.assertFalse(files[6].is_symlink) self.assertEqual(files[6].insert_count, 1) self.assertEqual(files[6].delete_count, 1) lines = files[6].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], b'diff --git a/readme2 b/readme2') self.assertEqual(lines[6], b'+Hello there') def test_parse_diff_with_index_range(self): """Testing Git diff parsing with an index range""" diff = (b'diff --git a/foo/bar b/foo/bar2\n' b'similarity index 88%\n' b'rename from foo/bar\n' b'rename to foo/bar2\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n' b'--- a/foo/bar\n' b'+++ b/foo/bar2\n' b'@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].orig_filename, b'foo/bar') self.assertEqual(files[0].modified_filename, b'foo/bar2') self.assertEqual(files[0].orig_file_details, b'612544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(files[0].modified_file_details, b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(files[0].insert_count, 1) self.assertEqual(files[0].delete_count, 1) def test_parse_diff_with_deleted_binary_files(self): """Testing Git diff parsing with deleted binary files""" diff = (b'diff --git a/foo.bin b/foo.bin\n' b'deleted file mode 100644\n' b'Binary file foo.bin has changed\n' b'diff --git a/bar.bin b/bar.bin\n' b'deleted file mode 100644\n' b'Binary file bar.bin has changed\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].orig_filename, b'foo.bin') self.assertEqual(files[0].modified_filename, b'foo.bin') self.assertEqual(files[0].binary, True) self.assertEqual(files[0].deleted, True) self.assertFalse(files[0].is_symlink) self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) self.assertEqual(files[1].orig_filename, b'bar.bin') self.assertEqual(files[1].modified_filename, b'bar.bin') self.assertEqual(files[1].binary, True) self.assertEqual(files[1].deleted, True) self.assertFalse(files[1].is_symlink) self.assertEqual(files[1].insert_count, 0) self.assertEqual(files[1].delete_count, 0) def test_parse_diff_with_all_headers(self): """Testing Git diff parsing and preserving all headers""" preamble = (b'From 38d8fa94a9aa0c5b27943bec31d94e880165f1e0 Mon Sep ' b'17 00:00:00 2001\n' b'From: Example Joe <*****@*****.**>\n' b'Date: Thu, 5 Apr 2012 00:41:12 -0700\n' b'Subject: [PATCH 1/1] Sample patch.\n' b'\n' b'This is a test summary.\n' b'\n' b'With a description.\n' b'---\n' b' foo/bar | 2 -+n' b' README | 2 -+n' b' 2 files changed, 2 insertions(+), 2 deletions(-)\n' b'\n') diff1 = (b'diff --git a/foo/bar b/foo/bar2\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n' b'--- a/foo/bar\n' b'+++ b/foo/bar2\n' b'@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n') diff2 = (b'diff --git a/README b/README\n' b'index 712544e4343bf04967eb5ea80257f6c64d6f42c7..' b'f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n' b'--- a/README\n' b'+++ b/README\n' b'@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n' b'-\n' b'1.7.1\n') diff = preamble + diff1 + diff2 files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].orig_filename, b'foo/bar') self.assertEqual(files[0].modified_filename, b'foo/bar2') self.assertEqual(files[0].orig_file_details, b'612544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(files[0].modified_file_details, b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(files[0].data, preamble + diff1) self.assertEqual(files[0].insert_count, 1) self.assertEqual(files[0].delete_count, 1) self.assertEqual(files[1].orig_filename, b'README') self.assertEqual(files[1].modified_filename, b'README') self.assertEqual(files[1].orig_file_details, b'712544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(files[1].modified_file_details, b'f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(files[1].data, diff2) self.assertEqual(files[1].insert_count, 1) self.assertEqual(files[1].delete_count, 2) def test_parse_diff_revision(self): """Testing Git revision number parsing""" self.assertEqual( self.tool.parse_diff_revision(filename=b'doc/readme', revision=b'bf544ea'), (b'doc/readme', b'bf544ea')) self.assertEqual( self.tool.parse_diff_revision(filename=b'/dev/null', revision=b'bf544ea'), (b'/dev/null', PRE_CREATION)) self.assertEqual( self.tool.parse_diff_revision(filename=b'/dev/null', revision=b'0000000'), (b'/dev/null', PRE_CREATION)) def test_parse_diff_with_copy_and_rename_same_file(self): """Testing Git diff parsing with copy and rename of same file""" diff = (b'diff --git a/foo/bar b/foo/bar2\n' b'similarity index 100%\n' b'copy from foo/bar\n' b'copy to foo/bar2\n' b'diff --git a/foo/bar b/foo/bar3\n' b'similarity index 92%\n' b'rename from foo/bar\n' b'rename to foo/bar3\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n' b'--- a/foo/bar\n' b'+++ b/foo/bar3\n' b'@@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) f = files[0] self.assertEqual(f.orig_filename, b'foo/bar') self.assertEqual(f.modified_filename, b'foo/bar2') self.assertEqual(f.orig_file_details, b'') self.assertEqual(f.modified_file_details, b'') self.assertEqual(f.insert_count, 0) self.assertEqual(f.delete_count, 0) self.assertFalse(f.moved) self.assertTrue(f.copied) self.assertFalse(f.is_symlink) f = files[1] self.assertEqual(f.orig_filename, b'foo/bar') self.assertEqual(f.modified_filename, b'foo/bar3') self.assertEqual(f.orig_file_details, b'612544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(f.modified_file_details, b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(f.insert_count, 1) self.assertEqual(f.delete_count, 1) self.assertTrue(f.moved) self.assertFalse(f.copied) self.assertFalse(f.is_symlink) def test_parse_diff_with_mode_change_and_rename(self): """Testing Git diff parsing with mode change and rename""" diff = (b'diff --git a/foo/bar b/foo/bar2\n' b'old mode 100755\n' b'new mode 100644\n' b'similarity index 99%\n' b'rename from foo/bar\n' b'rename to foo/bar2\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1\n' b'--- a/foo/bar\n' b'+++ b/foo/bar2\n' b'@@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.orig_filename, b'foo/bar') self.assertEqual(f.modified_filename, b'foo/bar2') self.assertEqual(f.orig_file_details, b'612544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(f.modified_file_details, b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(f.insert_count, 1) self.assertEqual(f.delete_count, 1) self.assertTrue(f.moved) self.assertFalse(f.copied) self.assertFalse(f.is_symlink) def test_diff_git_line_without_a_b(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes """ diff = (b'diff --git foo foo\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.orig_filename, b'foo') self.assertEqual(f.modified_filename, b'foo') self.assertTrue(f.deleted) self.assertFalse(f.is_symlink) def test_diff_git_line_without_a_b_quotes(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with quotes """ diff = (b'diff --git "foo" "foo"\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.orig_filename, b'foo') self.assertEqual(f.modified_filename, b'foo') self.assertTrue(f.deleted) self.assertFalse(f.is_symlink) def test_diff_git_line_without_a_b_and_spaces(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with spaces """ diff = (b'diff --git foo bar1 foo bar1\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.orig_filename, b'foo bar1') self.assertEqual(f.modified_filename, b'foo bar1') self.assertTrue(f.deleted) self.assertFalse(f.is_symlink) def test_diff_git_line_without_a_b_and_spaces_quotes(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with space and quotes """ diff = (b'diff --git "foo bar1" "foo bar1"\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.orig_filename, b'foo bar1') self.assertEqual(f.modified_filename, b'foo bar1') def test_diff_git_line_without_a_b_and_spaces_changed(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with spaces, with filename changes """ diff = (b'diff --git foo bar1 foo bar2\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') with self.assertRaises(DiffParserError) as cm: self.tool.get_parser(diff).parse() self.assertTrue( six.text_type(cm.exception).startswith( 'Unable to parse the "diff --git" line')) def test_diff_git_line_without_a_b_and_spaces_quotes_changed(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with spaces and quotes, with filename changes """ diff = (b'diff --git "foo bar1" "foo bar2"\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n' b'diff --git "foo bar1" foo\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n' b'diff --git foo "foo bar1"\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 3) f = files[0] self.assertEqual(f.orig_filename, b'foo bar1') self.assertEqual(f.modified_filename, b'foo bar2') self.assertTrue(f.deleted) self.assertFalse(f.is_symlink) f = files[1] self.assertEqual(f.orig_filename, b'foo bar1') self.assertEqual(f.modified_filename, b'foo') f = files[2] self.assertEqual(f.orig_filename, b'foo') self.assertEqual(f.modified_filename, b'foo bar1') def test_diff_git_symlink_added(self): """Testing parsing Git diff with symlink added""" diff = (b'diff --git a/link b/link\n' b'new file mode 120000\n' b'index 0000000..100b938\n' b'--- /dev/null\n' b'+++ b/link\n' b'@@ -0,0 +1 @@\n' b'+README\n' b'\\ No newline at end of file\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.orig_file_details, PRE_CREATION) self.assertEqual(f.modified_filename, b'link') self.assertTrue(f.is_symlink) def test_diff_git_symlink_changed(self): """Testing parsing Git diff with symlink changed""" diff = (b'diff --git a/link b/link\n' b'index 100b937..100b938 120000\n' b'--- a/link\n' b'+++ b/link\n' b'@@ -1 +1 @@\n' b'-README\n' b'\\ No newline at end of file\n' b'+README.md\n' b'\\ No newline at end of file\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.modified_filename, b'link') self.assertEqual(f.orig_filename, b'link') self.assertTrue(f.is_symlink) def test_diff_git_symlink_removed(self): """Testing parsing Git diff with symlink removed""" diff = (b'diff --git a/link b/link\n' b'deleted file mode 120000\n' b'index 100b938..0000000\n' b'--- a/link\n' b'+++ /dev/null\n' b'@@ -1 +0,0 @@\n' b'-README.txt\n' b'\\ No newline at end of file\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.orig_filename, b'link') self.assertTrue(f.deleted) self.assertTrue(f.is_symlink) def test_file_exists(self): """Testing GitTool.file_exists""" tool = self.tool self.assertTrue(tool.file_exists('readme', 'e965047')) self.assertTrue(tool.file_exists('readme', 'd6613f5')) self.assertFalse(tool.file_exists('readme', PRE_CREATION)) self.assertFalse(tool.file_exists('readme', 'fffffff')) self.assertFalse(tool.file_exists('readme2', 'fffffff')) # These sha's are valid, but commit and tree objects, not blobs. self.assertFalse(tool.file_exists('readme', 'a62df6c')) self.assertFalse(tool.file_exists('readme2', 'ccffbb4')) def test_get_file(self): """Testing GitTool.get_file""" tool = self.tool content = tool.get_file('readme', PRE_CREATION) self.assertIsInstance(content, bytes) self.assertEqual(content, b'') content = tool.get_file('readme', 'e965047') self.assertIsInstance(content, bytes) self.assertEqual(content, b'Hello\n') content = tool.get_file('readme', 'd6613f5') self.assertIsInstance(content, bytes) self.assertEqual(content, b'Hello there\n') content = tool.get_file('readme') self.assertIsInstance(content, bytes) self.assertEqual(content, b'Hello there\n') with self.assertRaises(SCMError): tool.get_file('') with self.assertRaises(FileNotFoundError): tool.get_file('', '0000000') with self.assertRaises(FileNotFoundError): tool.get_file('hello', '0000000') with self.assertRaises(FileNotFoundError): tool.get_file('readme', '0000000') def test_parse_diff_revision_with_remote_and_short_SHA1_error(self): """Testing GitTool.parse_diff_revision with remote files and short SHA1 error """ with self.assertRaises(ShortSHA1Error): self.remote_tool.parse_diff_revision(filename=b'README', revision=b'd7e96b3') def test_get_file_with_remote_and_short_SHA1_error(self): """Testing GitTool.get_file with remote files and short SHA1 error""" with self.assertRaises(ShortSHA1Error): self.remote_tool.get_file('README', 'd7e96b3') def test_valid_repository_https_username(self): """Testing GitClient.is_valid_repository with an HTTPS URL and external credentials """ client = GitClient('https://example.com/test.git', username='******', password='******') self.spy_on(client._run_git) client.is_valid_repository() self.assertEqual(client._run_git.calls[0].args[0], [ 'ls-remote', 'https://*****:*****@example.com/test.git', 'HEAD' ]) def test_raw_file_url_error(self): """Testing Repository.get_file re-fetches when raw file URL changes""" self.spy_on(self.remote_repository._get_file_uncached, call_fake=lambda a, b, x, y, z: 'first') self.assertEqual(self.remote_repository.get_file('PATH', 'd7e96b3'), 'first') # Ensure output of fake result matches. self.remote_repository._get_file_uncached.unspy() self.spy_on(self.remote_repository._get_file_uncached, call_fake=lambda a, b, x, y, z: 'second') # Grab from cache when no changes and change fake result to confirm # it is not called. self.assertEqual(self.remote_repository.get_file('PATH', 'd7e96b3'), 'first') self.remote_repository.raw_file_url = ( 'http://github.com/api/v2/yaml/blob/show/reviewboard/<revision>') # When raw_file_url changed, do not grab from cache and ensure output # equals second fake value. self.assertEqual(self.remote_repository.get_file('PATH', 'd7e96b3'), 'second') def test_get_file_exists_caching_with_raw_url(self): """Testing Repository.get_file_exists properly checks file existence in repository or cache when raw file URL changes """ self.spy_on(self.remote_repository._get_file_exists_uncached, call_fake=lambda a, b, x, y, z: True) # Use spy to put key into cache self.assertTrue( self.remote_repository.get_file_exists('PATH', 'd7e96b3')) # Remove spy to ensure key is still in cache without needing spy self.remote_repository._get_file_exists_uncached.unspy() self.assertTrue( self.remote_repository.get_file_exists('PATH', 'd7e96b3')) self.remote_repository.raw_file_url = ( 'http://github.com/api/v2/yaml/blob/show/reviewboard/<revision>') # Does not exist when raw_file_url changed because it is not cached. self.assertFalse( self.remote_repository.get_file_exists('PATH', 'd7e96b3'))
class GitTests(SpyAgency, SCMTestCase): """Unit tests for Git.""" fixtures = ['test_scmtools'] def setUp(self): super(GitTests, self).setUp() tool = Tool.objects.get(name='Git') self.local_repo_path = os.path.join(os.path.dirname(__file__), '..', 'testdata', 'git_repo') self.git_ssh_path = ('localhost:%s' % self.local_repo_path.replace('\\', '/')) remote_repo_path = '[email protected]:reviewboard/reviewboard.git' remote_repo_raw_url = ('http://github.com/api/v2/yaml/blob/show/' 'reviewboard/reviewboard/<revision>') self.repository = Repository(name='Git test repo', path=self.local_repo_path, tool=tool) self.remote_repository = Repository(name='Remote Git test repo', path=remote_repo_path, raw_file_url=remote_repo_raw_url, tool=tool) try: self.tool = self.repository.get_scmtool() self.remote_tool = self.remote_repository.get_scmtool() except ImportError: raise nose.SkipTest('git binary not found') def _read_fixture(self, filename): filename = os.path.join(os.path.dirname(__file__), '..', 'testdata', filename) with open(filename, 'r') as f: return f.read() def _get_file_in_diff(self, diff, filenum=0): files = self.tool.get_parser(diff).parse() self.assertTrue(filenum < len(files)) return files[filenum] def test_ssh(self): """Testing a SSH-backed git repository""" self._test_ssh(self.git_ssh_path) def test_ssh_with_site(self): """Testing a SSH-backed git repository with a LocalSite""" self._test_ssh_with_site(self.git_ssh_path) def test_filemode_diff(self): """Testing parsing filemode changes Git diff""" diff = ( b'diff --git a/testing b/testing\n' b'old mode 100755\n' b'new mode 100644\n' b'index e69de29..bcae657\n' b'--- a/testing\n' b'+++ b/testing\n' b'@@ -0,0 +1 @@\n' b'+ADD\n' b'diff --git a/testing2 b/testing2\n' b'old mode 100644\n' b'new mode 100755\n' ) file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, 'testing') self.assertEqual(file.newFile, 'testing') self.assertEqual(file.origInfo, 'e69de29') self.assertEqual(file.newInfo, 'bcae657') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(file.data.splitlines()[0], "diff --git a/testing b/testing") self.assertEqual(file.data.splitlines()[-1], "+ADD") self.assertEqual(file.insert_count, 1) self.assertEqual(file.delete_count, 0) def test_filemode_with_following_diff(self): """Testing parsing filemode changes with following Git diff""" diff = ( b'diff --git a/testing b/testing\n' b'old mode 100755\n' b'new mode 100644\n' b'index e69de29..bcae657\n' b'--- a/testing\n' b'+++ b/testing\n' b'@@ -0,0 +1 @@\n' b'+ADD\n' b'diff --git a/testing2 b/testing2\n' b'old mode 100644\n' b'new mode 100755\n' b'diff --git a/cfg/testcase.ini b/cfg/testcase.ini\n' b'index cc18ec8..5e70b73 100644\n' b'--- a/cfg/testcase.ini\n' b'+++ b/cfg/testcase.ini\n' b'@@ -1,6 +1,7 @@\n' b'+blah blah blah\n' b' [mysql]\n' b' host = localhost\n' b' port = 3306\n' b' user = user\n' b' pass = pass\n' b'-db = pyunit\n' b'+db = pyunit\n' ) file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, 'testing') self.assertEqual(file.newFile, 'testing') self.assertEqual(file.origInfo, 'e69de29') self.assertEqual(file.newInfo, 'bcae657') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(file.data.splitlines()[0], "diff --git a/testing b/testing") self.assertEqual(file.data.splitlines()[-1], "+ADD") self.assertEqual(file.insert_count, 1) self.assertEqual(file.delete_count, 0) file = self._get_file_in_diff(diff, 1) self.assertEqual(file.origFile, 'cfg/testcase.ini') self.assertEqual(file.newFile, 'cfg/testcase.ini') self.assertEqual(file.origInfo, 'cc18ec8') self.assertEqual(file.newInfo, '5e70b73') self.assertEqual(file.data.splitlines()[0], "diff --git a/cfg/testcase.ini b/cfg/testcase.ini") self.assertEqual(file.data.splitlines()[-1], '+db = pyunit') self.assertEqual(file.insert_count, 2) self.assertEqual(file.delete_count, 1) def test_simple_diff(self): """Testing parsing simple Git diff""" diff = ( b'diff --git a/cfg/testcase.ini b/cfg/testcase.ini\n' b'index cc18ec8..5e70b73 100644\n' b'--- a/cfg/testcase.ini\n' b'+++ b/cfg/testcase.ini\n' b'@@ -1,6 +1,7 @@\n' b'+blah blah blah\n' b' [mysql]\n' b' host = localhost\n' b' port = 3306\n' b' user = user\n' b' pass = pass\n' b'-db = pyunit\n' b'+db = pyunit\n' ) file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, 'cfg/testcase.ini') self.assertEqual(file.newFile, 'cfg/testcase.ini') self.assertEqual(file.origInfo, 'cc18ec8') self.assertEqual(file.newInfo, '5e70b73') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(len(file.data), 249) self.assertEqual(file.data.splitlines()[0], "diff --git a/cfg/testcase.ini b/cfg/testcase.ini") self.assertEqual(file.data.splitlines()[-1], "+db = pyunit") self.assertEqual(file.insert_count, 2) self.assertEqual(file.delete_count, 1) def test_diff_with_unicode(self): """Testing parsing Git diff with unicode characters""" diff = ('diff --git a/cfg/téstcase.ini b/cfg/téstcase.ini\n' 'index cc18ec8..5e70b73 100644\n' '--- a/cfg/téstcase.ini\n' '+++ b/cfg/téstcase.ini\n' '@@ -1,6 +1,7 @@\n' '+blah blah blah\n' ' [mysql]\n' ' hóst = localhost\n' ' pórt = 3306\n' ' user = user\n' ' pass = pass\n' '-db = pyunít\n' '+db = pyunít\n').encode('utf-8') file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, 'cfg/téstcase.ini') self.assertEqual(file.newFile, 'cfg/téstcase.ini') self.assertEqual(file.origInfo, 'cc18ec8') self.assertEqual(file.newInfo, '5e70b73') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(file.data.splitlines()[0].decode('utf-8'), 'diff --git a/cfg/téstcase.ini b/cfg/téstcase.ini') self.assertEqual(file.data.splitlines()[-1].decode('utf-8'), '+db = pyunít') self.assertEqual(file.insert_count, 2) self.assertEqual(file.delete_count, 1) def test_diff_with_tabs_after_filename(self): """Testing parsing Git diffs with tabs after the filename""" diff = ( b'diff --git a/README b/README\n' b'index 712544e4343bf04967eb5ea80257f6c64d6f42c7..' b'f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n' b'--- a/README\t\n' b'+++ b/README\t\n' b'@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n' b'-\n' b'1.7.1\n' ) files = self.tool.get_parser(diff).parse() self.assertEqual(files[0].origFile, 'README') self.assertEqual(files[0].newFile, 'README') self.assertEqual(files[0].origInfo, '712544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(files[0].newInfo, 'f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(files[0].data, diff) self.assertEqual(files[0].insert_count, 1) self.assertEqual(files[0].delete_count, 2) def test_new_file_diff(self): """Testing parsing Git diff with new file""" diff = ( b'diff --git a/IAMNEW b/IAMNEW\n' b'new file mode 100644\n' b'index 0000000..e69de29\n' b'--- /dev/null\n' b'+++ b/IAMNEW\n' b'@@ -0,0 +1,1 @@\n' b'+Hello\n' ) file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, 'IAMNEW') self.assertEqual(file.newFile, 'IAMNEW') self.assertEqual(file.origInfo, PRE_CREATION) self.assertEqual(file.newInfo, 'e69de29') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(len(file.data), 123) self.assertEqual(file.data.splitlines()[0], 'diff --git a/IAMNEW b/IAMNEW') self.assertEqual(file.data.splitlines()[-1], '+Hello') self.assertEqual(file.insert_count, 1) self.assertEqual(file.delete_count, 0) def test_new_file_no_content_diff(self): """Testing parsing Git diff new file, no content""" diff = ( b'diff --git a/newfile b/newfile\n' b'new file mode 100644\n' b'index 0000000..e69de29\n' ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, 'newfile') self.assertEqual(file.newFile, 'newfile') self.assertEqual(file.origInfo, PRE_CREATION) self.assertEqual(file.newInfo, 'e69de29') self.assertFalse(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) lines = file.data.splitlines() self.assertEqual(len(lines), 3) self.assertEqual(lines[0], 'diff --git a/newfile b/newfile') self.assertEqual(file.insert_count, 0) self.assertEqual(file.delete_count, 0) def test_new_file_no_content_with_following_diff(self): """Testing parsing Git diff new file, no content, with following""" diff = ( b'diff --git a/newfile b/newfile\n' b'new file mode 100644\n' b'index 0000000..e69de29\n' b'diff --git a/cfg/testcase.ini b/cfg/testcase.ini\n' b'index cc18ec8..5e70b73 100644\n' b'--- a/cfg/testcase.ini\n' b'+++ b/cfg/testcase.ini\n' b'@@ -1,6 +1,7 @@\n' b'+blah blah blah\n' b' [mysql]\n' b' host = localhost\n' b' port = 3306\n' b' user = user\n' b' pass = pass\n' b'-db = pyunit\n' b'+db = pyunit\n' ) files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].origFile, 'newfile') self.assertEqual(files[0].newFile, 'newfile') self.assertEqual(files[0].origInfo, PRE_CREATION) self.assertEqual(files[0].newInfo, 'e69de29') self.assertFalse(files[0].binary) self.assertFalse(files[0].deleted) self.assertFalse(files[0].is_symlink) lines = files[0].data.splitlines() self.assertEqual(len(lines), 3) self.assertEqual(lines[0], 'diff --git a/newfile b/newfile') self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) self.assertEqual(files[1].origFile, 'cfg/testcase.ini') self.assertEqual(files[1].newFile, 'cfg/testcase.ini') self.assertEqual(files[1].origInfo, 'cc18ec8') self.assertEqual(files[1].newInfo, '5e70b73') lines = files[1].data.splitlines() self.assertEqual(len(lines), 13) self.assertEqual(lines[0], 'diff --git a/cfg/testcase.ini b/cfg/testcase.ini') self.assertEqual(lines[-1], '+db = pyunit') self.assertEqual(files[1].insert_count, 2) self.assertEqual(files[1].delete_count, 1) def test_del_file_diff(self): """Testing parsing Git diff with deleted file""" diff = ( b'diff --git a/OLDFILE b/OLDFILE\n' b'deleted file mode 100644\n' b'index 8ebcb01..0000000\n' b'--- a/OLDFILE\n' b'+++ /dev/null\n' b'@@ -1,1 +0,0 @@\n' b'-Goodbye\n' ) file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, 'OLDFILE') self.assertEqual(file.newFile, 'OLDFILE') self.assertEqual(file.origInfo, '8ebcb01') self.assertEqual(file.newInfo, '0000000') self.assertFalse(file.binary) self.assertTrue(file.deleted) self.assertFalse(file.is_symlink) self.assertEqual(len(file.data), 132) self.assertEqual(file.data.splitlines()[0], 'diff --git a/OLDFILE b/OLDFILE') self.assertEqual(file.data.splitlines()[-1], '-Goodbye') self.assertEqual(file.insert_count, 0) self.assertEqual(file.delete_count, 1) def test_del_file_no_content_diff(self): """Testing parsing Git diff with deleted file, no content""" diff = (b'diff --git a/empty b/empty\n' b'deleted file mode 100644\n' b'index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].origFile, 'empty') self.assertEqual(files[0].newFile, 'empty') self.assertEqual(files[0].origInfo, 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391') self.assertEqual(files[0].newInfo, '0000000000000000000000000000000000000000') self.assertFalse(files[0].binary) self.assertTrue(files[0].deleted) self.assertFalse(files[0].is_symlink) self.assertEqual(len(files[0].data), 141) self.assertEqual(files[0].data.splitlines()[0], 'diff --git a/empty b/empty') self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) def test_del_file_no_content_with_following_diff(self): """Testing parsing Git diff with deleted file, no content, with following """ diff = (b'diff --git a/empty b/empty\n' b'deleted file mode 100644\n' b'index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..' b'0000000000000000000000000000000000000000\n' b'diff --git a/foo/bar b/foo/bar\n' b'index 484ba93ef5b0aed5b72af8f4e9dc4cfd10ef1a81..' b'0ae4095ddfe7387d405bd53bd59bbb5d861114c5 100644\n' b'--- a/foo/bar\n' b'+++ b/foo/bar\n' b'@@ -1 +1,2 @@\n' b'+Hello!\n' b'blah\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].origFile, 'empty') self.assertEqual(files[0].newFile, 'empty') self.assertEqual(files[0].origInfo, 'e69de29bb2d1d6434b8b29ae775ad8c2e48c5391') self.assertEqual(files[0].newInfo, '0000000000000000000000000000000000000000') self.assertFalse(files[0].binary) self.assertTrue(files[0].deleted) self.assertFalse(files[0].is_symlink) self.assertEqual(len(files[0].data), 141) self.assertEqual(files[0].data.splitlines()[0], 'diff --git a/empty b/empty') self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) self.assertEqual(files[1].origFile, 'foo/bar') self.assertEqual(files[1].newFile, 'foo/bar') self.assertEqual(files[1].origInfo, '484ba93ef5b0aed5b72af8f4e9dc4cfd10ef1a81') self.assertEqual(files[1].newInfo, '0ae4095ddfe7387d405bd53bd59bbb5d861114c5') self.assertFalse(files[1].binary) self.assertFalse(files[1].deleted) self.assertFalse(files[1].is_symlink) lines = files[1].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], 'diff --git a/foo/bar b/foo/bar') self.assertEqual(lines[5], '+Hello!') self.assertEqual(files[1].insert_count, 1) self.assertEqual(files[1].delete_count, 0) def test_binary_diff(self): """Testing parsing Git diff with binary""" diff = ( b'diff --git a/pysvn-1.5.1.tar.gz b/pysvn-1.5.1.tar.gz\n' b'new file mode 100644\n' b'index 0000000..86b520c\n' b'Binary files /dev/null and b/pysvn-1.5.1.tar.gz differ\n' ) file = self._get_file_in_diff(diff) self.assertEqual(file.origFile, 'pysvn-1.5.1.tar.gz') self.assertEqual(file.newFile, 'pysvn-1.5.1.tar.gz') self.assertEqual(file.origInfo, PRE_CREATION) self.assertEqual(file.newInfo, '86b520c') self.assertTrue(file.binary) self.assertFalse(file.deleted) self.assertFalse(file.is_symlink) lines = file.data.splitlines() self.assertEqual(len(lines), 4) self.assertEqual( lines[0], 'diff --git a/pysvn-1.5.1.tar.gz b/pysvn-1.5.1.tar.gz') self.assertEqual( lines[3], 'Binary files /dev/null and b/pysvn-1.5.1.tar.gz differ') self.assertEqual(file.insert_count, 0) self.assertEqual(file.delete_count, 0) def test_complex_diff(self): """Testing parsing Git diff with existing and new files""" diff = self._read_fixture('git_complex.diff') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 7) self.assertEqual(files[0].origFile, 'cfg/testcase.ini') self.assertEqual(files[0].newFile, 'cfg/testcase.ini') self.assertEqual(files[0].origInfo, '5e35098') self.assertEqual(files[0].newInfo, 'e254ef4') self.assertFalse(files[0].binary) self.assertFalse(files[0].deleted) self.assertFalse(files[0].is_symlink) self.assertEqual(files[0].insert_count, 2) self.assertEqual(files[0].delete_count, 1) self.assertEqual(len(files[0].data), 549) self.assertEqual(files[0].data.splitlines()[0], 'diff --git a/cfg/testcase.ini b/cfg/testcase.ini') self.assertEqual(files[0].data.splitlines()[13], ' if isinstance(value, basestring):') self.assertEqual(files[1].origFile, 'tests/models.py') self.assertEqual(files[1].newFile, 'tests/models.py') self.assertEqual(files[1].origInfo, PRE_CREATION) self.assertEqual(files[1].newInfo, 'e69de29') self.assertFalse(files[1].binary) self.assertFalse(files[1].deleted) self.assertFalse(files[1].is_symlink) self.assertEqual(files[1].insert_count, 0) self.assertEqual(files[1].delete_count, 0) lines = files[1].data.splitlines() self.assertEqual(len(lines), 3) self.assertEqual(lines[0], 'diff --git a/tests/models.py b/tests/models.py') self.assertEqual(files[2].origFile, 'tests/tests.py') self.assertEqual(files[2].newFile, 'tests/tests.py') self.assertEqual(files[2].origInfo, PRE_CREATION) self.assertEqual(files[2].newInfo, 'e279a06') self.assertFalse(files[2].binary) self.assertFalse(files[2].deleted) self.assertFalse(files[2].is_symlink) self.assertEqual(files[2].insert_count, 2) self.assertEqual(files[2].delete_count, 0) lines = files[2].data.splitlines() self.assertEqual(len(lines), 8) self.assertEqual(lines[0], 'diff --git a/tests/tests.py b/tests/tests.py') self.assertEqual(lines[7], '+This is some new content') self.assertEqual(files[3].origFile, 'pysvn-1.5.1.tar.gz') self.assertEqual(files[3].newFile, 'pysvn-1.5.1.tar.gz') self.assertEqual(files[3].origInfo, PRE_CREATION) self.assertEqual(files[3].newInfo, '86b520c') self.assertTrue(files[3].binary) self.assertFalse(files[3].deleted) self.assertFalse(files[3].is_symlink) self.assertEqual(files[3].insert_count, 0) self.assertEqual(files[3].delete_count, 0) lines = files[3].data.splitlines() self.assertEqual(len(lines), 4) self.assertEqual( lines[0], 'diff --git a/pysvn-1.5.1.tar.gz b/pysvn-1.5.1.tar.gz') self.assertEqual(lines[3], 'Binary files /dev/null and b/pysvn-1.5.1.tar.gz ' 'differ') self.assertEqual(files[4].origFile, 'readme') self.assertEqual(files[4].newFile, 'readme') self.assertEqual(files[4].origInfo, '5e35098') self.assertEqual(files[4].newInfo, 'e254ef4') self.assertFalse(files[4].binary) self.assertFalse(files[4].deleted) self.assertFalse(files[4].is_symlink) self.assertEqual(files[4].insert_count, 1) self.assertEqual(files[4].delete_count, 1) lines = files[4].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], 'diff --git a/readme b/readme') self.assertEqual(lines[6], '+Hello there') self.assertEqual(files[5].origFile, 'OLDFILE') self.assertEqual(files[5].newFile, 'OLDFILE') self.assertEqual(files[5].origInfo, '8ebcb01') self.assertEqual(files[5].newInfo, '0000000') self.assertFalse(files[5].binary) self.assertTrue(files[5].deleted) self.assertFalse(files[5].is_symlink) self.assertEqual(files[5].insert_count, 0) self.assertEqual(files[5].delete_count, 1) lines = files[5].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], 'diff --git a/OLDFILE b/OLDFILE') self.assertEqual(lines[6], '-Goodbye') self.assertEqual(files[6].origFile, 'readme2') self.assertEqual(files[6].newFile, 'readme2') self.assertEqual(files[6].origInfo, '5e43098') self.assertEqual(files[6].newInfo, 'e248ef4') self.assertFalse(files[6].binary) self.assertFalse(files[6].deleted) self.assertFalse(files[6].is_symlink) self.assertEqual(files[6].insert_count, 1) self.assertEqual(files[6].delete_count, 1) lines = files[6].data.splitlines() self.assertEqual(len(lines), 7) self.assertEqual(lines[0], 'diff --git a/readme2 b/readme2') self.assertEqual(lines[6], '+Hello there') def test_parse_diff_with_index_range(self): """Testing Git diff parsing with an index range""" diff = (b'diff --git a/foo/bar b/foo/bar2\n' b'similarity index 88%\n' b'rename from foo/bar\n' b'rename to foo/bar2\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n' b'--- a/foo/bar\n' b'+++ b/foo/bar2\n' b'@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) self.assertEqual(files[0].origFile, 'foo/bar') self.assertEqual(files[0].newFile, 'foo/bar2') self.assertEqual(files[0].origInfo, '612544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(files[0].newInfo, 'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(files[0].insert_count, 1) self.assertEqual(files[0].delete_count, 1) def test_parse_diff_with_deleted_binary_files(self): """Testing Git diff parsing with deleted binary files""" diff = (b'diff --git a/foo.bin b/foo.bin\n' b'deleted file mode 100644\n' b'Binary file foo.bin has changed\n' b'diff --git a/bar.bin b/bar.bin\n' b'deleted file mode 100644\n' b'Binary file bar.bin has changed\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].origFile, 'foo.bin') self.assertEqual(files[0].newFile, 'foo.bin') self.assertEqual(files[0].binary, True) self.assertEqual(files[0].deleted, True) self.assertFalse(files[0].is_symlink) self.assertEqual(files[0].insert_count, 0) self.assertEqual(files[0].delete_count, 0) self.assertEqual(files[1].origFile, 'bar.bin') self.assertEqual(files[1].newFile, 'bar.bin') self.assertEqual(files[1].binary, True) self.assertEqual(files[1].deleted, True) self.assertFalse(files[1].is_symlink) self.assertEqual(files[1].insert_count, 0) self.assertEqual(files[1].delete_count, 0) def test_parse_diff_with_all_headers(self): """Testing Git diff parsing and preserving all headers""" preamble = ( b'From 38d8fa94a9aa0c5b27943bec31d94e880165f1e0 Mon Sep ' b'17 00:00:00 2001\n' b'From: Example Joe <*****@*****.**>\n' b'Date: Thu, 5 Apr 2012 00:41:12 -0700\n' b'Subject: [PATCH 1/1] Sample patch.\n' b'\n' b'This is a test summary.\n' b'\n' b'With a description.\n' b'---\n' b' foo/bar | 2 -+n' b' README | 2 -+n' b' 2 files changed, 2 insertions(+), 2 deletions(-)\n' b'\n') diff1 = ( b'diff --git a/foo/bar b/foo/bar2\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n' b'--- a/foo/bar\n' b'+++ b/foo/bar2\n' b'@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n') diff2 = ( b'diff --git a/README b/README\n' b'index 712544e4343bf04967eb5ea80257f6c64d6f42c7..' b'f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n' b'--- a/README\n' b'+++ b/README\n' b'@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n' b'-\n' b'1.7.1\n') diff = preamble + diff1 + diff2 files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) self.assertEqual(files[0].origFile, 'foo/bar') self.assertEqual(files[0].newFile, 'foo/bar2') self.assertEqual(files[0].origInfo, '612544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(files[0].newInfo, 'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(files[0].data, preamble + diff1) self.assertEqual(files[0].insert_count, 1) self.assertEqual(files[0].delete_count, 1) self.assertEqual(files[1].origFile, 'README') self.assertEqual(files[1].newFile, 'README') self.assertEqual(files[1].origInfo, '712544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(files[1].newInfo, 'f88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(files[1].data, diff2) self.assertEqual(files[1].insert_count, 1) self.assertEqual(files[1].delete_count, 2) def test_parse_diff_revision(self): """Testing Git revision number parsing""" self.assertEqual( self.tool.parse_diff_revision('doc/readme', 'bf544ea'), ('doc/readme', 'bf544ea')) self.assertEqual( self.tool.parse_diff_revision('/dev/null', 'bf544ea'), ('/dev/null', PRE_CREATION)) self.assertEqual( self.tool.parse_diff_revision('/dev/null', '0000000'), ('/dev/null', PRE_CREATION)) def test_parse_diff_with_copy_and_rename_same_file(self): """Testing Git diff parsing with copy and rename of same file""" diff = (b'diff --git a/foo/bar b/foo/bar2\n' b'similarity index 100%\n' b'copy from foo/bar\n' b'copy to foo/bar2\n' b'diff --git a/foo/bar b/foo/bar3\n' b'similarity index 92%\n' b'rename from foo/bar\n' b'rename to foo/bar3\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1 100644\n' b'--- a/foo/bar\n' b'+++ b/foo/bar3\n' b'@@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 2) f = files[0] self.assertEqual(f.origFile, 'foo/bar') self.assertEqual(f.newFile, 'foo/bar2') self.assertEqual(f.origInfo, '') self.assertEqual(f.newInfo, '') self.assertEqual(f.insert_count, 0) self.assertEqual(f.delete_count, 0) self.assertFalse(f.moved) self.assertTrue(f.copied) self.assertFalse(f.is_symlink) f = files[1] self.assertEqual(f.origFile, 'foo/bar') self.assertEqual(f.newFile, 'foo/bar3') self.assertEqual(f.origInfo, '612544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(f.newInfo, 'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(f.insert_count, 1) self.assertEqual(f.delete_count, 1) self.assertTrue(f.moved) self.assertFalse(f.copied) self.assertFalse(f.is_symlink) def test_parse_diff_with_mode_change_and_rename(self): """Testing Git diff parsing with mode change and rename""" diff = (b'diff --git a/foo/bar b/foo/bar2\n' b'old mode 100755\n' b'new mode 100644\n' b'similarity index 99%\n' b'rename from foo/bar\n' b'rename to foo/bar2\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1\n' b'--- a/foo/bar\n' b'+++ b/foo/bar2\n' b'@@ -1,1 +1,1 @@\n' b'-blah blah\n' b'+blah\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origFile, 'foo/bar') self.assertEqual(f.newFile, 'foo/bar2') self.assertEqual(f.origInfo, '612544e4343bf04967eb5ea80257f6c64d6f42c7') self.assertEqual(f.newInfo, 'e88b7f15c03d141d0bb38c8e49bb6c411ebfe1f1') self.assertEqual(f.insert_count, 1) self.assertEqual(f.delete_count, 1) self.assertTrue(f.moved) self.assertFalse(f.copied) self.assertFalse(f.is_symlink) def test_diff_git_line_without_a_b(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes """ diff = (b'diff --git foo foo\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origFile, 'foo') self.assertEqual(f.newFile, 'foo') self.assertTrue(f.deleted) self.assertFalse(f.is_symlink) def test_diff_git_line_without_a_b_quotes(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with quotes """ diff = (b'diff --git "foo" "foo"\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origFile, 'foo') self.assertEqual(f.newFile, 'foo') self.assertTrue(f.deleted) self.assertFalse(f.is_symlink) def test_diff_git_line_without_a_b_and_spaces(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with spaces """ diff = (b'diff --git foo bar1 foo bar1\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origFile, 'foo bar1') self.assertEqual(f.newFile, 'foo bar1') self.assertTrue(f.deleted) self.assertFalse(f.is_symlink) def test_diff_git_line_without_a_b_and_spaces_quotes(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with space and quotes """ diff = (b'diff --git "foo bar1" "foo bar1"\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origFile, 'foo bar1') self.assertEqual(f.newFile, 'foo bar1') def test_diff_git_line_without_a_b_and_spaces_changed(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with spaces, with filename changes """ diff = (b'diff --git foo bar1 foo bar2\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') with self.assertRaises(DiffParserError) as cm: self.tool.get_parser(diff).parse() self.assertTrue(six.text_type(cm.exception).startswith( 'Unable to parse the "diff --git" line')) def test_diff_git_line_without_a_b_and_spaces_quotes_changed(self): """Testing parsing Git diff with deleted file without a/ and b/ filename prefixes and with spaces and quotes, with filename changes """ diff = (b'diff --git "foo bar1" "foo bar2"\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n' b'diff --git "foo bar1" foo\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n' b'diff --git foo "foo bar1"\n' b'deleted file mode 100644\n' b'index 612544e4343bf04967eb5ea80257f6c64d6f42c7..' b'0000000000000000000000000000000000000000\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 3) f = files[0] self.assertEqual(f.origFile, 'foo bar1') self.assertEqual(f.newFile, 'foo bar2') self.assertTrue(f.deleted) self.assertFalse(f.is_symlink) f = files[1] self.assertEqual(f.origFile, 'foo bar1') self.assertEqual(f.newFile, 'foo') f = files[2] self.assertEqual(f.origFile, 'foo') self.assertEqual(f.newFile, 'foo bar1') def test_diff_git_symlink_added(self): """Testing parsing Git diff with symlink added""" diff = (b'diff --git a/link b/link\n' b'new file mode 120000\n' b'index 0000000..100b938\n' b'--- /dev/null\n' b'+++ b/link\n' b'@@ -0,0 +1 @@\n' b'+README\n' b'\\ No newline at end of file\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origInfo, PRE_CREATION) self.assertEqual(f.newFile, 'link') self.assertTrue(f.is_symlink) def test_diff_git_symlink_changed(self): """Testing parsing Git diff with symlink changed""" diff = (b'diff --git a/link b/link\n' b'index 100b937..100b938 120000\n' b'--- a/link\n' b'+++ b/link\n' b'@@ -1 +1 @@\n' b'-README\n' b'\\ No newline at end of file\n' b'+README.md\n' b'\\ No newline at end of file\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.newFile, 'link') self.assertEqual(f.origFile, 'link') self.assertTrue(f.is_symlink) def test_diff_git_symlink_removed(self): """Testing parsing Git diff with symlink removed""" diff = (b'diff --git a/link b/link\n' b'deleted file mode 120000\n' b'index 100b938..0000000\n' b'--- a/link\n' b'+++ /dev/null\n' b'@@ -1 +0,0 @@\n' b'-README.txt\n' b'\\ No newline at end of file\n') files = self.tool.get_parser(diff).parse() self.assertEqual(len(files), 1) f = files[0] self.assertEqual(f.origFile, 'link') self.assertTrue(f.deleted) self.assertTrue(f.is_symlink) def test_file_exists(self): """Testing GitTool.file_exists""" self.assertTrue(self.tool.file_exists('readme', 'e965047')) self.assertTrue(self.tool.file_exists('readme', 'd6613f5')) self.assertTrue(not self.tool.file_exists('readme', PRE_CREATION)) self.assertTrue(not self.tool.file_exists('readme', 'fffffff')) self.assertTrue(not self.tool.file_exists('readme2', 'fffffff')) # these sha's are valid, but commit and tree objects, not blobs self.assertTrue(not self.tool.file_exists('readme', 'a62df6c')) self.assertTrue(not self.tool.file_exists('readme2', 'ccffbb4')) def test_get_file(self): """Testing GitTool.get_file""" self.assertEqual(self.tool.get_file('readme', PRE_CREATION), b'') self.assertTrue( isinstance(self.tool.get_file('readme', 'e965047'), bytes)) self.assertEqual(self.tool.get_file('readme', 'e965047'), b'Hello\n') self.assertEqual(self.tool.get_file('readme', 'd6613f5'), b'Hello there\n') self.assertEqual(self.tool.get_file('readme'), b'Hello there\n') self.assertRaises(SCMError, lambda: self.tool.get_file('')) self.assertRaises(FileNotFoundError, lambda: self.tool.get_file('', '0000000')) self.assertRaises(FileNotFoundError, lambda: self.tool.get_file('hello', '0000000')) self.assertRaises(FileNotFoundError, lambda: self.tool.get_file('readme', '0000000')) def test_parse_diff_revision_with_remote_and_short_SHA1_error(self): """Testing GitTool.parse_diff_revision with remote files and short SHA1 error """ self.assertRaises( ShortSHA1Error, lambda: self.remote_tool.parse_diff_revision('README', 'd7e96b3')) def test_get_file_with_remote_and_short_SHA1_error(self): """Testing GitTool.get_file with remote files and short SHA1 error""" self.assertRaises( ShortSHA1Error, lambda: self.remote_tool.get_file('README', 'd7e96b3')) def test_valid_repository_https_username(self): """Testing GitClient.is_valid_repository with an HTTPS URL and external credentials """ client = GitClient('https://example.com/test.git', username='******', password='******') self.spy_on(client._run_git) client.is_valid_repository() self.assertEqual(client._run_git.calls[0].args[0], ['ls-remote', 'https://*****:*****@example.com/test.git', 'HEAD']) def test_raw_file_url_error(self): """Testing Repository.get_file re-fetches when raw file URL changes""" self.spy_on(self.remote_repository._get_file_uncached, call_fake=lambda a, b, x, y, z: 'first') self.assertEqual(self.remote_repository.get_file('PATH', 'd7e96b3'), 'first') # Ensure output of fake result matches. self.remote_repository._get_file_uncached.unspy() self.spy_on(self.remote_repository._get_file_uncached, call_fake=lambda a, b, x, y, z: 'second') # Grab from cache when no changes and change fake result to confirm # it is not called. self.assertEqual(self.remote_repository.get_file('PATH', 'd7e96b3'), 'first') self.remote_repository.raw_file_url = ( 'http://github.com/api/v2/yaml/blob/show/reviewboard/<revision>') # When raw_file_url changed, do not grab from cache and ensure output # equals second fake value. self.assertEqual(self.remote_repository.get_file('PATH', 'd7e96b3'), 'second') def test_get_file_exists_caching_with_raw_url(self): """Testing Repository.get_file_exists properly checks file existence in repository or cache when raw file URL changes """ self.spy_on(self.remote_repository._get_file_exists_uncached, call_fake=lambda a, b, x, y, z: True) # Use spy to put key into cache self.assertTrue(self.remote_repository.get_file_exists('PATH', 'd7e96b3')) # Remove spy to ensure key is still in cache without needing spy self.remote_repository._get_file_exists_uncached.unspy() self.assertTrue(self.remote_repository.get_file_exists('PATH', 'd7e96b3')) self.remote_repository.raw_file_url = ( 'http://github.com/api/v2/yaml/blob/show/reviewboard/<revision>') # Does not exist when raw_file_url changed because it is not cached. self.assertFalse(self.remote_repository.get_file_exists('PATH', 'd7e96b3'))