##// END OF EJS Templates
diffs: handle paths with quotes in diffs.
dan -
r3826:ab69d1e3 stable
parent child Browse files
Show More
@@ -0,0 +1,7 b''
1 diff --git "a/\"><img src=x onerror=prompt(0)>/\"><img src=x onerror=prompt(1)>.txt" "b/\"><img src=x onerror=prompt(0)>/\"><img src=x onerror=prompt(1)>.txt"
2 index e69de29..8eb97de 100644
3 --- "a/\"><img src=x onerror=prompt(0)>/\"><img src=x onerror=prompt(1)>.txt"
4 +++ "b/\"><img src=x onerror=prompt(0)>/\"><img src=x onerror=prompt(1)>.txt"
5 @@ -0,0 +1 @@
6 +Ehlo eglo
7 \ No newline at end of file
@@ -1,49 +1,49 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2014-2019 RhodeCode GmbH
3 # Copyright (C) 2014-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 GIT diff module
22 GIT diff module
23 """
23 """
24
24
25 import re
25 import re
26
26
27 from rhodecode.lib.vcs.backends import base
27 from rhodecode.lib.vcs.backends import base
28
28
29
29
30 class GitDiff(base.Diff):
30 class GitDiff(base.Diff):
31
31
32 _header_re = re.compile(r"""
32 _header_re = re.compile(r"""
33 #^diff[ ]--git
33 #^diff[ ]--git
34 [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n
34 [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n
35 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
35 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
36 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
36 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
37 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%(?:\n|$))?
37 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%(?:\n|$))?
38 (?:^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n
38 (?:^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n
39 ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))?
39 ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))?
40 (?:^copy[ ]from[ ](?P<copy_from>[^\r\n]+)\n
40 (?:^copy[ ]from[ ](?P<copy_from>[^\r\n]+)\n
41 ^copy[ ]to[ ](?P<copy_to>[^\r\n]+)(?:\n|$))?
41 ^copy[ ]to[ ](?P<copy_to>[^\r\n]+)(?:\n|$))?
42 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
42 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
43 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
43 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
44 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
44 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
45 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
45 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
46 (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))?
46 (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))?
47 (?:^---[ ](a/(?P<a_file>.+)|/dev/null)(?:\n|$))?
47 (?:^---[ ]("?a/(?P<a_file>.+)|/dev/null)(?:\n|$))?
48 (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)(?:\n|$))?
48 (?:^\+\+\+[ ]("?b/(?P<b_file>.+)|/dev/null)(?:\n|$))?
49 """, re.VERBOSE | re.MULTILINE)
49 """, re.VERBOSE | re.MULTILINE)
@@ -1,49 +1,49 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2014-2019 RhodeCode GmbH
3 # Copyright (C) 2014-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 GIT diff module
22 HG diff module
23 """
23 """
24
24
25 import re
25 import re
26
26
27 from rhodecode.lib.vcs.backends import base
27 from rhodecode.lib.vcs.backends import base
28
28
29
29
30 class MercurialDiff(base.Diff):
30 class MercurialDiff(base.Diff):
31
31
32 _header_re = re.compile(r"""
32 _header_re = re.compile(r"""
33 #^diff[ ]--git
33 #^diff[ ]--git
34 [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n
34 [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n
35 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
35 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
36 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
36 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
37 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%(?:\n|$))?
37 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%(?:\n|$))?
38 (?:^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n
38 (?:^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n
39 ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))?
39 ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))?
40 (?:^copy[ ]from[ ](?P<copy_from>[^\r\n]+)\n
40 (?:^copy[ ]from[ ](?P<copy_from>[^\r\n]+)\n
41 ^copy[ ]to[ ](?P<copy_to>[^\r\n]+)(?:\n|$))?
41 ^copy[ ]to[ ](?P<copy_to>[^\r\n]+)(?:\n|$))?
42 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
42 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
43 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
43 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
44 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
44 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
45 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
45 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
46 (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))?
46 (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))?
47 (?:^---[ ](a/(?P<a_file>.+)|/dev/null)(?:\n|$))?
47 (?:^---[ ]("?a/(?P<a_file>.+)|/dev/null)(?:\n|$))?
48 (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)(?:\n|$))?
48 (?:^\+\+\+[ ]("?b/(?P<b_file>.+)|/dev/null)(?:\n|$))?
49 """, re.VERBOSE | re.MULTILINE)
49 """, re.VERBOSE | re.MULTILINE)
@@ -1,52 +1,51 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2014-2019 RhodeCode GmbH
3 # Copyright (C) 2014-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
22 """
21 """
23 SVN diff module
22 SVN diff module
24 """
23 """
25
24
26 import re
25 import re
27
26
28 from rhodecode.lib.vcs.backends import base
27 from rhodecode.lib.vcs.backends import base
29
28
30
29
31 class SubversionDiff(base.Diff):
30 class SubversionDiff(base.Diff):
32
31
33 _meta_re = re.compile(r"""
32 _meta_re = re.compile(r"""
34 (?:^(?P<svn_bin_patch>Cannot[ ]display:[ ]file[ ]marked[ ]as[ ]a[ ]binary[ ]type.)(?:\n|$))?
33 (?:^(?P<svn_bin_patch>Cannot[ ]display:[ ]file[ ]marked[ ]as[ ]a[ ]binary[ ]type.)(?:\n|$))?
35 """, re.VERBOSE | re.MULTILINE)
34 """, re.VERBOSE | re.MULTILINE)
36
35
37 _header_re = re.compile(r"""
36 _header_re = re.compile(r"""
38 #^diff[ ]--git
37 #^diff[ ]--git
39 [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n
38 [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n
40 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
39 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
41 ^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n
40 ^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n
42 ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))?
41 ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))?
43 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
42 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
44 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
43 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
45 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
44 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
46 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
45 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
47 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
46 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
48 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
47 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
49 (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))?
48 (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))?
50 (?:^---[ ](a/(?P<a_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))?
49 (?:^---[ ]("?a/(?P<a_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))?
51 (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))?
50 (?:^\+\+\+[ ]("?b/(?P<b_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))?
52 """, re.VERBOSE | re.MULTILINE)
51 """, re.VERBOSE | re.MULTILINE)
@@ -1,817 +1,825 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2019 RhodeCode GmbH
3 # Copyright (C) 2010-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import textwrap
21 import textwrap
22
22
23 import mock
23 import mock
24 import pytest
24 import pytest
25
25
26 from rhodecode.lib.codeblocks import DiffSet
26 from rhodecode.lib.codeblocks import DiffSet
27 from rhodecode.lib.diffs import (
27 from rhodecode.lib.diffs import (
28 DiffProcessor,
28 DiffProcessor,
29 NEW_FILENODE, DEL_FILENODE, MOD_FILENODE, RENAMED_FILENODE,
29 NEW_FILENODE, DEL_FILENODE, MOD_FILENODE, RENAMED_FILENODE,
30 CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE)
30 CHMOD_FILENODE, BIN_FILENODE, COPIED_FILENODE)
31 from rhodecode.lib.utils2 import AttributeDict
31 from rhodecode.lib.utils2 import AttributeDict
32 from rhodecode.lib.vcs.backends.git import GitCommit
32 from rhodecode.lib.vcs.backends.git import GitCommit
33 from rhodecode.tests.fixture import Fixture, no_newline_id_generator
33 from rhodecode.tests.fixture import Fixture, no_newline_id_generator
34 from rhodecode.lib.vcs.backends.git.repository import GitDiff
34 from rhodecode.lib.vcs.backends.git.repository import GitDiff
35 from rhodecode.lib.vcs.backends.hg.repository import MercurialDiff
35 from rhodecode.lib.vcs.backends.hg.repository import MercurialDiff
36 from rhodecode.lib.vcs.backends.svn.repository import SubversionDiff
36 from rhodecode.lib.vcs.backends.svn.repository import SubversionDiff
37
37
38 fixture = Fixture()
38 fixture = Fixture()
39
39
40
40
41 def test_diffprocessor_as_html_with_comments():
41 def test_diffprocessor_as_html_with_comments():
42 raw_diff = textwrap.dedent('''
42 raw_diff = textwrap.dedent('''
43 diff --git a/setup.py b/setup.py
43 diff --git a/setup.py b/setup.py
44 index 5b36422..cfd698e 100755
44 index 5b36422..cfd698e 100755
45 --- a/setup.py
45 --- a/setup.py
46 +++ b/setup.py
46 +++ b/setup.py
47 @@ -2,7 +2,7 @@
47 @@ -2,7 +2,7 @@
48 #!/usr/bin/python
48 #!/usr/bin/python
49 # Setup file for X
49 # Setup file for X
50 # Copyright (C) No one
50 # Copyright (C) No one
51 -
51 -
52 +x
52 +x
53 try:
53 try:
54 from setuptools import setup, Extension
54 from setuptools import setup, Extension
55 except ImportError:
55 except ImportError:
56 ''')
56 ''')
57 diff = GitDiff(raw_diff)
57 diff = GitDiff(raw_diff)
58 processor = DiffProcessor(diff)
58 processor = DiffProcessor(diff)
59 processor.prepare()
59 processor.prepare()
60
60
61 # Note that the cell with the context in line 5 (in the html) has the
61 # Note that the cell with the context in line 5 (in the html) has the
62 # no-comment class, which will prevent the add comment icon to be displayed.
62 # no-comment class, which will prevent the add comment icon to be displayed.
63 expected_html = textwrap.dedent('''
63 expected_html = textwrap.dedent('''
64 <table class="code-difftable">
64 <table class="code-difftable">
65 <tr class="line context">
65 <tr class="line context">
66 <td class="add-comment-line"><span class="add-comment-content"></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
66 <td class="add-comment-line"><span class="add-comment-content"></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
67 <td class="lineno old">...</td>
67 <td class="lineno old">...</td>
68 <td class="lineno new">...</td>
68 <td class="lineno new">...</td>
69 <td class="code no-comment">
69 <td class="code no-comment">
70 <pre>@@ -2,7 +2,7 @@
70 <pre>@@ -2,7 +2,7 @@
71 </pre>
71 </pre>
72 </td>
72 </td>
73 </tr>
73 </tr>
74 <tr class="line unmod">
74 <tr class="line unmod">
75 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
75 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
76 <td id="setuppy_o2" class="lineno old"><a href="#setuppy_o2" class="tooltip"
76 <td id="setuppy_o2" class="lineno old"><a href="#setuppy_o2" class="tooltip"
77 title="Click to select line">2</a></td>
77 title="Click to select line">2</a></td>
78 <td id="setuppy_n2" class="lineno new"><a href="#setuppy_n2" class="tooltip"
78 <td id="setuppy_n2" class="lineno new"><a href="#setuppy_n2" class="tooltip"
79 title="Click to select line">2</a></td>
79 title="Click to select line">2</a></td>
80 <td class="code">
80 <td class="code">
81 <pre>#!/usr/bin/python
81 <pre>#!/usr/bin/python
82 </pre>
82 </pre>
83 </td>
83 </td>
84 </tr>
84 </tr>
85 <tr class="line unmod">
85 <tr class="line unmod">
86 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
86 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
87 <td id="setuppy_o3" class="lineno old"><a href="#setuppy_o3" class="tooltip"
87 <td id="setuppy_o3" class="lineno old"><a href="#setuppy_o3" class="tooltip"
88 title="Click to select line">3</a></td>
88 title="Click to select line">3</a></td>
89 <td id="setuppy_n3" class="lineno new"><a href="#setuppy_n3" class="tooltip"
89 <td id="setuppy_n3" class="lineno new"><a href="#setuppy_n3" class="tooltip"
90 title="Click to select line">3</a></td>
90 title="Click to select line">3</a></td>
91 <td class="code">
91 <td class="code">
92 <pre># Setup file for X
92 <pre># Setup file for X
93 </pre>
93 </pre>
94 </td>
94 </td>
95 </tr>
95 </tr>
96 <tr class="line unmod">
96 <tr class="line unmod">
97 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
97 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
98 <td id="setuppy_o4" class="lineno old"><a href="#setuppy_o4" class="tooltip"
98 <td id="setuppy_o4" class="lineno old"><a href="#setuppy_o4" class="tooltip"
99 title="Click to select line">4</a></td>
99 title="Click to select line">4</a></td>
100 <td id="setuppy_n4" class="lineno new"><a href="#setuppy_n4" class="tooltip"
100 <td id="setuppy_n4" class="lineno new"><a href="#setuppy_n4" class="tooltip"
101 title="Click to select line">4</a></td>
101 title="Click to select line">4</a></td>
102 <td class="code">
102 <td class="code">
103 <pre># Copyright (C) No one
103 <pre># Copyright (C) No one
104 </pre>
104 </pre>
105 </td>
105 </td>
106 </tr>
106 </tr>
107 <tr class="line del">
107 <tr class="line del">
108 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
108 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
109 <td id="setuppy_o5" class="lineno old"><a href="#setuppy_o5" class="tooltip"
109 <td id="setuppy_o5" class="lineno old"><a href="#setuppy_o5" class="tooltip"
110 title="Click to select line">5</a></td>
110 title="Click to select line">5</a></td>
111 <td class="lineno new"><a href="#setuppy_n" class="tooltip"
111 <td class="lineno new"><a href="#setuppy_n" class="tooltip"
112 title="Click to select line"></a></td>
112 title="Click to select line"></a></td>
113 <td class="code">
113 <td class="code">
114 <pre>
114 <pre>
115 </pre>
115 </pre>
116 </td>
116 </td>
117 </tr>
117 </tr>
118 <tr class="line add">
118 <tr class="line add">
119 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
119 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
120 <td class="lineno old"><a href="#setuppy_o" class="tooltip"
120 <td class="lineno old"><a href="#setuppy_o" class="tooltip"
121 title="Click to select line"></a></td>
121 title="Click to select line"></a></td>
122 <td id="setuppy_n5" class="lineno new"><a href="#setuppy_n5" class="tooltip"
122 <td id="setuppy_n5" class="lineno new"><a href="#setuppy_n5" class="tooltip"
123 title="Click to select line">5</a></td>
123 title="Click to select line">5</a></td>
124 <td class="code">
124 <td class="code">
125 <pre><ins>x</ins>
125 <pre><ins>x</ins>
126 </pre>
126 </pre>
127 </td>
127 </td>
128 </tr>
128 </tr>
129 <tr class="line unmod">
129 <tr class="line unmod">
130 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
130 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
131 <td id="setuppy_o6" class="lineno old"><a href="#setuppy_o6" class="tooltip"
131 <td id="setuppy_o6" class="lineno old"><a href="#setuppy_o6" class="tooltip"
132 title="Click to select line">6</a></td>
132 title="Click to select line">6</a></td>
133 <td id="setuppy_n6" class="lineno new"><a href="#setuppy_n6" class="tooltip"
133 <td id="setuppy_n6" class="lineno new"><a href="#setuppy_n6" class="tooltip"
134 title="Click to select line">6</a></td>
134 title="Click to select line">6</a></td>
135 <td class="code">
135 <td class="code">
136 <pre>try:
136 <pre>try:
137 </pre>
137 </pre>
138 </td>
138 </td>
139 </tr>
139 </tr>
140 <tr class="line unmod">
140 <tr class="line unmod">
141 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
141 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
142 <td id="setuppy_o7" class="lineno old"><a href="#setuppy_o7" class="tooltip"
142 <td id="setuppy_o7" class="lineno old"><a href="#setuppy_o7" class="tooltip"
143 title="Click to select line">7</a></td>
143 title="Click to select line">7</a></td>
144 <td id="setuppy_n7" class="lineno new"><a href="#setuppy_n7" class="tooltip"
144 <td id="setuppy_n7" class="lineno new"><a href="#setuppy_n7" class="tooltip"
145 title="Click to select line">7</a></td>
145 title="Click to select line">7</a></td>
146 <td class="code">
146 <td class="code">
147 <pre> from setuptools import setup, Extension
147 <pre> from setuptools import setup, Extension
148 </pre>
148 </pre>
149 </td>
149 </td>
150 </tr>
150 </tr>
151 <tr class="line unmod">
151 <tr class="line unmod">
152 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
152 <td class="add-comment-line"><span class="add-comment-content"><a href="#"><span class="icon-comment-add"></span></a></span></td><td class="comment-toggle tooltip" title="Toggle Comment Thread"><i class="icon-comment"></i></td>
153 <td id="setuppy_o8" class="lineno old"><a href="#setuppy_o8" class="tooltip"
153 <td id="setuppy_o8" class="lineno old"><a href="#setuppy_o8" class="tooltip"
154 title="Click to select line">8</a></td>
154 title="Click to select line">8</a></td>
155 <td id="setuppy_n8" class="lineno new"><a href="#setuppy_n8" class="tooltip"
155 <td id="setuppy_n8" class="lineno new"><a href="#setuppy_n8" class="tooltip"
156 title="Click to select line">8</a></td>
156 title="Click to select line">8</a></td>
157 <td class="code">
157 <td class="code">
158 <pre>except ImportError:
158 <pre>except ImportError:
159 </pre>
159 </pre>
160 </td>
160 </td>
161 </tr>
161 </tr>
162 </table>
162 </table>
163 ''').strip()
163 ''').strip()
164 html = processor.as_html(enable_comments=True).replace('\t', ' ')
164 html = processor.as_html(enable_comments=True).replace('\t', ' ')
165
165
166 assert html == expected_html
166 assert html == expected_html
167
167
168
168
169 class TestMixedFilenameEncodings(object):
169 class TestMixedFilenameEncodings(object):
170
170
171 @pytest.fixture(scope="class")
171 @pytest.fixture(scope="class")
172 def raw_diff(self):
172 def raw_diff(self):
173 return fixture.load_resource(
173 return fixture.load_resource(
174 'hg_diff_mixed_filename_encodings.diff')
174 'hg_diff_mixed_filename_encodings.diff')
175
175
176 @pytest.fixture
176 @pytest.fixture
177 def processor(self, raw_diff):
177 def processor(self, raw_diff):
178 diff = MercurialDiff(raw_diff)
178 diff = MercurialDiff(raw_diff)
179 processor = DiffProcessor(diff)
179 processor = DiffProcessor(diff)
180 return processor
180 return processor
181
181
182 def test_filenames_are_decoded_to_unicode(self, processor):
182 def test_filenames_are_decoded_to_unicode(self, processor):
183 diff_data = processor.prepare()
183 diff_data = processor.prepare()
184 filenames = [item['filename'] for item in diff_data]
184 filenames = [item['filename'] for item in diff_data]
185 assert filenames == [
185 assert filenames == [
186 u'spΓ€cial-utf8.txt', u'spοΏ½cial-cp1252.txt', u'spοΏ½cial-latin1.txt']
186 u'spΓ€cial-utf8.txt', u'spοΏ½cial-cp1252.txt', u'spοΏ½cial-latin1.txt']
187
187
188 def test_raw_diff_is_decoded_to_unicode(self, processor):
188 def test_raw_diff_is_decoded_to_unicode(self, processor):
189 diff_data = processor.prepare()
189 diff_data = processor.prepare()
190 raw_diffs = [item['raw_diff'] for item in diff_data]
190 raw_diffs = [item['raw_diff'] for item in diff_data]
191 new_file_message = u'\nnew file mode 100644\n'
191 new_file_message = u'\nnew file mode 100644\n'
192 expected_raw_diffs = [
192 expected_raw_diffs = [
193 u' a/spΓ€cial-utf8.txt b/spΓ€cial-utf8.txt' + new_file_message,
193 u' a/spΓ€cial-utf8.txt b/spΓ€cial-utf8.txt' + new_file_message,
194 u' a/spοΏ½cial-cp1252.txt b/spοΏ½cial-cp1252.txt' + new_file_message,
194 u' a/spοΏ½cial-cp1252.txt b/spοΏ½cial-cp1252.txt' + new_file_message,
195 u' a/spοΏ½cial-latin1.txt b/spοΏ½cial-latin1.txt' + new_file_message]
195 u' a/spοΏ½cial-latin1.txt b/spοΏ½cial-latin1.txt' + new_file_message]
196 assert raw_diffs == expected_raw_diffs
196 assert raw_diffs == expected_raw_diffs
197
197
198 def test_as_raw_preserves_the_encoding(self, processor, raw_diff):
198 def test_as_raw_preserves_the_encoding(self, processor, raw_diff):
199 assert processor.as_raw() == raw_diff
199 assert processor.as_raw() == raw_diff
200
200
201
201
202 # TODO: mikhail: format the following data structure properly
202 # TODO: mikhail: format the following data structure properly
203 DIFF_FIXTURES = [
203 DIFF_FIXTURES = [
204 ('hg',
204 ('hg',
205 'hg_diff_add_single_binary_file.diff',
205 'hg_diff_add_single_binary_file.diff',
206 [('US Warszawa.jpg', 'A',
206 [('US Warszawa.jpg', 'A',
207 {'added': 0,
207 {'added': 0,
208 'deleted': 0,
208 'deleted': 0,
209 'binary': True,
209 'binary': True,
210 'ops': {NEW_FILENODE: 'new file 100755',
210 'ops': {NEW_FILENODE: 'new file 100755',
211 BIN_FILENODE: 'binary diff hidden'}}),
211 BIN_FILENODE: 'binary diff hidden'}}),
212 ]),
212 ]),
213 ('hg',
213 ('hg',
214 'hg_diff_mod_single_binary_file.diff',
214 'hg_diff_mod_single_binary_file.diff',
215 [('US Warszawa.jpg', 'M',
215 [('US Warszawa.jpg', 'M',
216 {'added': 0,
216 {'added': 0,
217 'deleted': 0,
217 'deleted': 0,
218 'binary': True,
218 'binary': True,
219 'ops': {MOD_FILENODE: 'modified file',
219 'ops': {MOD_FILENODE: 'modified file',
220 BIN_FILENODE: 'binary diff hidden'}}),
220 BIN_FILENODE: 'binary diff hidden'}}),
221 ]),
221 ]),
222 ('hg',
222 ('hg',
223 'hg_diff_mod_single_file_and_rename_and_chmod.diff',
223 'hg_diff_mod_single_file_and_rename_and_chmod.diff',
224 [('README', 'M',
224 [('README', 'M',
225 {'added': 3,
225 {'added': 3,
226 'deleted': 0,
226 'deleted': 0,
227 'binary': False,
227 'binary': False,
228 'ops': {MOD_FILENODE: 'modified file',
228 'ops': {MOD_FILENODE: 'modified file',
229 RENAMED_FILENODE: 'file renamed from README.rst to README',
229 RENAMED_FILENODE: 'file renamed from README.rst to README',
230 CHMOD_FILENODE: 'modified file chmod 100755 => 100644'}}),
230 CHMOD_FILENODE: 'modified file chmod 100755 => 100644'}}),
231 ]),
231 ]),
232 ('hg',
232 ('hg',
233 'hg_diff_no_newline.diff',
233 'hg_diff_no_newline.diff',
234 [('server.properties', 'M',
234 [('server.properties', 'M',
235 {'added': 2,
235 {'added': 2,
236 'deleted': 1,
236 'deleted': 1,
237 'binary': False,
237 'binary': False,
238 'ops': {MOD_FILENODE: 'modified file'}}),
238 'ops': {MOD_FILENODE: 'modified file'}}),
239 ]),
239 ]),
240 ('hg',
240 ('hg',
241 'hg_diff_mod_file_and_rename.diff',
241 'hg_diff_mod_file_and_rename.diff',
242 [('README.rst', 'M',
242 [('README.rst', 'M',
243 {'added': 3,
243 {'added': 3,
244 'deleted': 0,
244 'deleted': 0,
245 'binary': False,
245 'binary': False,
246 'ops': {MOD_FILENODE: 'modified file',
246 'ops': {MOD_FILENODE: 'modified file',
247 RENAMED_FILENODE: 'file renamed from README to README.rst'}}),
247 RENAMED_FILENODE: 'file renamed from README to README.rst'}}),
248 ]),
248 ]),
249 ('hg',
249 ('hg',
250 'hg_diff_del_single_binary_file.diff',
250 'hg_diff_del_single_binary_file.diff',
251 [('US Warszawa.jpg', 'D',
251 [('US Warszawa.jpg', 'D',
252 {'added': 0,
252 {'added': 0,
253 'deleted': 0,
253 'deleted': 0,
254 'binary': True,
254 'binary': True,
255 'ops': {DEL_FILENODE: 'deleted file',
255 'ops': {DEL_FILENODE: 'deleted file',
256 BIN_FILENODE: 'binary diff hidden'}}),
256 BIN_FILENODE: 'binary diff hidden'}}),
257 ]),
257 ]),
258 ('hg',
258 ('hg',
259 'hg_diff_chmod_and_mod_single_binary_file.diff',
259 'hg_diff_chmod_and_mod_single_binary_file.diff',
260 [('gravatar.png', 'M',
260 [('gravatar.png', 'M',
261 {'added': 0,
261 {'added': 0,
262 'deleted': 0,
262 'deleted': 0,
263 'binary': True,
263 'binary': True,
264 'ops': {CHMOD_FILENODE: 'modified file chmod 100644 => 100755',
264 'ops': {CHMOD_FILENODE: 'modified file chmod 100644 => 100755',
265 BIN_FILENODE: 'binary diff hidden'}}),
265 BIN_FILENODE: 'binary diff hidden'}}),
266 ]),
266 ]),
267 ('hg',
267 ('hg',
268 'hg_diff_chmod.diff',
268 'hg_diff_chmod.diff',
269 [('file', 'M',
269 [('file', 'M',
270 {'added': 0,
270 {'added': 0,
271 'deleted': 0,
271 'deleted': 0,
272 'binary': True,
272 'binary': True,
273 'ops': {CHMOD_FILENODE: 'modified file chmod 100755 => 100644'}}),
273 'ops': {CHMOD_FILENODE: 'modified file chmod 100755 => 100644'}}),
274 ]),
274 ]),
275 ('hg',
275 ('hg',
276 'hg_diff_rename_file.diff',
276 'hg_diff_rename_file.diff',
277 [('file_renamed', 'M',
277 [('file_renamed', 'M',
278 {'added': 0,
278 {'added': 0,
279 'deleted': 0,
279 'deleted': 0,
280 'binary': True,
280 'binary': True,
281 'ops': {RENAMED_FILENODE: 'file renamed from file to file_renamed'}}),
281 'ops': {RENAMED_FILENODE: 'file renamed from file to file_renamed'}}),
282 ]),
282 ]),
283 ('hg',
283 ('hg',
284 'hg_diff_rename_and_chmod_file.diff',
284 'hg_diff_rename_and_chmod_file.diff',
285 [('README', 'M',
285 [('README', 'M',
286 {'added': 0,
286 {'added': 0,
287 'deleted': 0,
287 'deleted': 0,
288 'binary': True,
288 'binary': True,
289 'ops': {CHMOD_FILENODE: 'modified file chmod 100644 => 100755',
289 'ops': {CHMOD_FILENODE: 'modified file chmod 100644 => 100755',
290 RENAMED_FILENODE: 'file renamed from README.rst to README'}}),
290 RENAMED_FILENODE: 'file renamed from README.rst to README'}}),
291 ]),
291 ]),
292 ('hg',
292 ('hg',
293 'hg_diff_binary_and_normal.diff',
293 'hg_diff_binary_and_normal.diff',
294 [('img/baseline-10px.png', 'A',
294 [('img/baseline-10px.png', 'A',
295 {'added': 0,
295 {'added': 0,
296 'deleted': 0,
296 'deleted': 0,
297 'binary': True,
297 'binary': True,
298 'ops': {NEW_FILENODE: 'new file 100644',
298 'ops': {NEW_FILENODE: 'new file 100644',
299 BIN_FILENODE: 'binary diff hidden'}}),
299 BIN_FILENODE: 'binary diff hidden'}}),
300 ('js/jquery/hashgrid.js', 'A',
300 ('js/jquery/hashgrid.js', 'A',
301 {'added': 340,
301 {'added': 340,
302 'deleted': 0,
302 'deleted': 0,
303 'binary': False,
303 'binary': False,
304 'ops': {NEW_FILENODE: 'new file 100755'}}),
304 'ops': {NEW_FILENODE: 'new file 100755'}}),
305 ('index.html', 'M',
305 ('index.html', 'M',
306 {'added': 3,
306 {'added': 3,
307 'deleted': 2,
307 'deleted': 2,
308 'binary': False,
308 'binary': False,
309 'ops': {MOD_FILENODE: 'modified file'}}),
309 'ops': {MOD_FILENODE: 'modified file'}}),
310 ('less/docs.less', 'M',
310 ('less/docs.less', 'M',
311 {'added': 34,
311 {'added': 34,
312 'deleted': 0,
312 'deleted': 0,
313 'binary': False,
313 'binary': False,
314 'ops': {MOD_FILENODE: 'modified file'}}),
314 'ops': {MOD_FILENODE: 'modified file'}}),
315 ('less/scaffolding.less', 'M',
315 ('less/scaffolding.less', 'M',
316 {'added': 1,
316 {'added': 1,
317 'deleted': 3,
317 'deleted': 3,
318 'binary': False,
318 'binary': False,
319 'ops': {MOD_FILENODE: 'modified file'}}),
319 'ops': {MOD_FILENODE: 'modified file'}}),
320 ('readme.markdown', 'M',
320 ('readme.markdown', 'M',
321 {'added': 1,
321 {'added': 1,
322 'deleted': 10,
322 'deleted': 10,
323 'binary': False,
323 'binary': False,
324 'ops': {MOD_FILENODE: 'modified file'}}),
324 'ops': {MOD_FILENODE: 'modified file'}}),
325 ('img/baseline-20px.png', 'D',
325 ('img/baseline-20px.png', 'D',
326 {'added': 0,
326 {'added': 0,
327 'deleted': 0,
327 'deleted': 0,
328 'binary': True,
328 'binary': True,
329 'ops': {DEL_FILENODE: 'deleted file',
329 'ops': {DEL_FILENODE: 'deleted file',
330 BIN_FILENODE: 'binary diff hidden'}}),
330 BIN_FILENODE: 'binary diff hidden'}}),
331 ('js/global.js', 'D',
331 ('js/global.js', 'D',
332 {'added': 0,
332 {'added': 0,
333 'deleted': 75,
333 'deleted': 75,
334 'binary': False,
334 'binary': False,
335 'ops': {DEL_FILENODE: 'deleted file'}})
335 'ops': {DEL_FILENODE: 'deleted file'}})
336 ]),
336 ]),
337 ('git',
337 ('git',
338 'git_diff_chmod.diff',
338 'git_diff_chmod.diff',
339 [('work-horus.xls', 'M',
339 [('work-horus.xls', 'M',
340 {'added': 0,
340 {'added': 0,
341 'deleted': 0,
341 'deleted': 0,
342 'binary': True,
342 'binary': True,
343 'ops': {CHMOD_FILENODE: 'modified file chmod 100644 => 100755'}})
343 'ops': {CHMOD_FILENODE: 'modified file chmod 100644 => 100755'}})
344 ]),
344 ]),
345 ('git',
345 ('git',
346 'git_diff_js_chars.diff',
347 [('\\"><img src=x onerror=prompt(0)>/\\"><img src=x onerror=prompt(1)>.txt', 'M',
348 {'added': 1,
349 'deleted': 0,
350 'binary': False,
351 'ops': {MOD_FILENODE: 'modified file'}})
352 ]),
353 ('git',
346 'git_diff_rename_file.diff',
354 'git_diff_rename_file.diff',
347 [('file.xls', 'M',
355 [('file.xls', 'M',
348 {'added': 0,
356 {'added': 0,
349 'deleted': 0,
357 'deleted': 0,
350 'binary': True,
358 'binary': True,
351 'ops': {
359 'ops': {
352 RENAMED_FILENODE: 'file renamed from work-horus.xls to file.xls'}})
360 RENAMED_FILENODE: 'file renamed from work-horus.xls to file.xls'}})
353 ]),
361 ]),
354 ('git',
362 ('git',
355 'git_diff_mod_single_binary_file.diff',
363 'git_diff_mod_single_binary_file.diff',
356 [('US Warszawa.jpg', 'M',
364 [('US Warszawa.jpg', 'M',
357 {'added': 0,
365 {'added': 0,
358 'deleted': 0,
366 'deleted': 0,
359 'binary': True,
367 'binary': True,
360 'ops': {MOD_FILENODE: 'modified file',
368 'ops': {MOD_FILENODE: 'modified file',
361 BIN_FILENODE: 'binary diff hidden'}})
369 BIN_FILENODE: 'binary diff hidden'}})
362 ]),
370 ]),
363 ('git',
371 ('git',
364 'git_diff_binary_and_normal.diff',
372 'git_diff_binary_and_normal.diff',
365 [('img/baseline-10px.png', 'A',
373 [('img/baseline-10px.png', 'A',
366 {'added': 0,
374 {'added': 0,
367 'deleted': 0,
375 'deleted': 0,
368 'binary': True,
376 'binary': True,
369 'ops': {NEW_FILENODE: 'new file 100644',
377 'ops': {NEW_FILENODE: 'new file 100644',
370 BIN_FILENODE: 'binary diff hidden'}}),
378 BIN_FILENODE: 'binary diff hidden'}}),
371 ('js/jquery/hashgrid.js', 'A',
379 ('js/jquery/hashgrid.js', 'A',
372 {'added': 340,
380 {'added': 340,
373 'deleted': 0,
381 'deleted': 0,
374 'binary': False,
382 'binary': False,
375 'ops': {NEW_FILENODE: 'new file 100755'}}),
383 'ops': {NEW_FILENODE: 'new file 100755'}}),
376 ('index.html', 'M',
384 ('index.html', 'M',
377 {'added': 3,
385 {'added': 3,
378 'deleted': 2,
386 'deleted': 2,
379 'binary': False,
387 'binary': False,
380 'ops': {MOD_FILENODE: 'modified file'}}),
388 'ops': {MOD_FILENODE: 'modified file'}}),
381 ('less/docs.less', 'M',
389 ('less/docs.less', 'M',
382 {'added': 34,
390 {'added': 34,
383 'deleted': 0,
391 'deleted': 0,
384 'binary': False,
392 'binary': False,
385 'ops': {MOD_FILENODE: 'modified file'}}),
393 'ops': {MOD_FILENODE: 'modified file'}}),
386 ('less/scaffolding.less', 'M',
394 ('less/scaffolding.less', 'M',
387 {'added': 1,
395 {'added': 1,
388 'deleted': 3,
396 'deleted': 3,
389 'binary': False,
397 'binary': False,
390 'ops': {MOD_FILENODE: 'modified file'}}),
398 'ops': {MOD_FILENODE: 'modified file'}}),
391 ('readme.markdown', 'M',
399 ('readme.markdown', 'M',
392 {'added': 1,
400 {'added': 1,
393 'deleted': 10,
401 'deleted': 10,
394 'binary': False,
402 'binary': False,
395 'ops': {MOD_FILENODE: 'modified file'}}),
403 'ops': {MOD_FILENODE: 'modified file'}}),
396 ('img/baseline-20px.png', 'D',
404 ('img/baseline-20px.png', 'D',
397 {'added': 0,
405 {'added': 0,
398 'deleted': 0,
406 'deleted': 0,
399 'binary': True,
407 'binary': True,
400 'ops': {DEL_FILENODE: 'deleted file',
408 'ops': {DEL_FILENODE: 'deleted file',
401 BIN_FILENODE: 'binary diff hidden'}}),
409 BIN_FILENODE: 'binary diff hidden'}}),
402 ('js/global.js', 'D',
410 ('js/global.js', 'D',
403 {'added': 0,
411 {'added': 0,
404 'deleted': 75,
412 'deleted': 75,
405 'binary': False,
413 'binary': False,
406 'ops': {DEL_FILENODE: 'deleted file'}}),
414 'ops': {DEL_FILENODE: 'deleted file'}}),
407 ]),
415 ]),
408 ('hg',
416 ('hg',
409 'diff_with_diff_data.diff',
417 'diff_with_diff_data.diff',
410 [('vcs/backends/base.py', 'M',
418 [('vcs/backends/base.py', 'M',
411 {'added': 18,
419 {'added': 18,
412 'deleted': 2,
420 'deleted': 2,
413 'binary': False,
421 'binary': False,
414 'ops': {MOD_FILENODE: 'modified file'}}),
422 'ops': {MOD_FILENODE: 'modified file'}}),
415 ('vcs/backends/git/repository.py', 'M',
423 ('vcs/backends/git/repository.py', 'M',
416 {'added': 46,
424 {'added': 46,
417 'deleted': 15,
425 'deleted': 15,
418 'binary': False,
426 'binary': False,
419 'ops': {MOD_FILENODE: 'modified file'}}),
427 'ops': {MOD_FILENODE: 'modified file'}}),
420 ('vcs/backends/hg.py', 'M',
428 ('vcs/backends/hg.py', 'M',
421 {'added': 22,
429 {'added': 22,
422 'deleted': 3,
430 'deleted': 3,
423 'binary': False,
431 'binary': False,
424 'ops': {MOD_FILENODE: 'modified file'}}),
432 'ops': {MOD_FILENODE: 'modified file'}}),
425 ('vcs/tests/test_git.py', 'M',
433 ('vcs/tests/test_git.py', 'M',
426 {'added': 5,
434 {'added': 5,
427 'deleted': 5,
435 'deleted': 5,
428 'binary': False,
436 'binary': False,
429 'ops': {MOD_FILENODE: 'modified file'}}),
437 'ops': {MOD_FILENODE: 'modified file'}}),
430 ('vcs/tests/test_repository.py', 'M',
438 ('vcs/tests/test_repository.py', 'M',
431 {'added': 174,
439 {'added': 174,
432 'deleted': 2,
440 'deleted': 2,
433 'binary': False,
441 'binary': False,
434 'ops': {MOD_FILENODE: 'modified file'}}),
442 'ops': {MOD_FILENODE: 'modified file'}}),
435 ]),
443 ]),
436 ('hg',
444 ('hg',
437 'hg_diff_copy_file.diff',
445 'hg_diff_copy_file.diff',
438 [('file2', 'M',
446 [('file2', 'M',
439 {'added': 0,
447 {'added': 0,
440 'deleted': 0,
448 'deleted': 0,
441 'binary': True,
449 'binary': True,
442 'ops': {COPIED_FILENODE: 'file copied from file1 to file2'}}),
450 'ops': {COPIED_FILENODE: 'file copied from file1 to file2'}}),
443 ]),
451 ]),
444 ('hg',
452 ('hg',
445 'hg_diff_copy_and_modify_file.diff',
453 'hg_diff_copy_and_modify_file.diff',
446 [('file3', 'M',
454 [('file3', 'M',
447 {'added': 1,
455 {'added': 1,
448 'deleted': 0,
456 'deleted': 0,
449 'binary': False,
457 'binary': False,
450 'ops': {COPIED_FILENODE: 'file copied from file2 to file3',
458 'ops': {COPIED_FILENODE: 'file copied from file2 to file3',
451 MOD_FILENODE: 'modified file'}}),
459 MOD_FILENODE: 'modified file'}}),
452 ]),
460 ]),
453 ('hg',
461 ('hg',
454 'hg_diff_copy_and_chmod_file.diff',
462 'hg_diff_copy_and_chmod_file.diff',
455 [('file4', 'M',
463 [('file4', 'M',
456 {'added': 0,
464 {'added': 0,
457 'deleted': 0,
465 'deleted': 0,
458 'binary': True,
466 'binary': True,
459 'ops': {COPIED_FILENODE: 'file copied from file3 to file4',
467 'ops': {COPIED_FILENODE: 'file copied from file3 to file4',
460 CHMOD_FILENODE: 'modified file chmod 100644 => 100755'}}),
468 CHMOD_FILENODE: 'modified file chmod 100644 => 100755'}}),
461 ]),
469 ]),
462 ('hg',
470 ('hg',
463 'hg_diff_copy_chmod_and_edit_file.diff',
471 'hg_diff_copy_chmod_and_edit_file.diff',
464 [('file5', 'M',
472 [('file5', 'M',
465 {'added': 2,
473 {'added': 2,
466 'deleted': 1,
474 'deleted': 1,
467 'binary': False,
475 'binary': False,
468 'ops': {COPIED_FILENODE: 'file copied from file4 to file5',
476 'ops': {COPIED_FILENODE: 'file copied from file4 to file5',
469 CHMOD_FILENODE: 'modified file chmod 100755 => 100644',
477 CHMOD_FILENODE: 'modified file chmod 100755 => 100644',
470 MOD_FILENODE: 'modified file'}})]),
478 MOD_FILENODE: 'modified file'}})]),
471
479
472 # Diffs to validate rename and copy file with space in its name
480 # Diffs to validate rename and copy file with space in its name
473 ('git',
481 ('git',
474 'git_diff_rename_file_with_spaces.diff',
482 'git_diff_rename_file_with_spaces.diff',
475 [('file_with_ two spaces.txt', 'M',
483 [('file_with_ two spaces.txt', 'M',
476 {'added': 0,
484 {'added': 0,
477 'deleted': 0,
485 'deleted': 0,
478 'binary': True,
486 'binary': True,
479 'ops': {
487 'ops': {
480 RENAMED_FILENODE: (
488 RENAMED_FILENODE: (
481 'file renamed from file_with_ spaces.txt to file_with_ '
489 'file renamed from file_with_ spaces.txt to file_with_ '
482 ' two spaces.txt')}
490 ' two spaces.txt')}
483 }), ]),
491 }), ]),
484 ('hg',
492 ('hg',
485 'hg_diff_rename_file_with_spaces.diff',
493 'hg_diff_rename_file_with_spaces.diff',
486 [('file_changed _.txt', 'M',
494 [('file_changed _.txt', 'M',
487 {'added': 0,
495 {'added': 0,
488 'deleted': 0,
496 'deleted': 0,
489 'binary': True,
497 'binary': True,
490 'ops': {
498 'ops': {
491 RENAMED_FILENODE: (
499 RENAMED_FILENODE: (
492 'file renamed from file_ with update.txt to file_changed'
500 'file renamed from file_ with update.txt to file_changed'
493 ' _.txt')}
501 ' _.txt')}
494 }), ]),
502 }), ]),
495 ('hg',
503 ('hg',
496 'hg_diff_copy_file_with_spaces.diff',
504 'hg_diff_copy_file_with_spaces.diff',
497 [('file_copied_ with spaces.txt', 'M',
505 [('file_copied_ with spaces.txt', 'M',
498 {'added': 0,
506 {'added': 0,
499 'deleted': 0,
507 'deleted': 0,
500 'binary': True,
508 'binary': True,
501 'ops': {
509 'ops': {
502 COPIED_FILENODE: (
510 COPIED_FILENODE: (
503 'file copied from file_changed_without_spaces.txt to'
511 'file copied from file_changed_without_spaces.txt to'
504 ' file_copied_ with spaces.txt')}
512 ' file_copied_ with spaces.txt')}
505 }),
513 }),
506 ]),
514 ]),
507
515
508 # special signs from git
516 # special signs from git
509 ('git',
517 ('git',
510 'git_diff_binary_special_files.diff',
518 'git_diff_binary_special_files.diff',
511 [('css/_Icon\\r', 'A',
519 [('css/_Icon\\r', 'A',
512 {'added': 0,
520 {'added': 0,
513 'deleted': 0,
521 'deleted': 0,
514 'binary': True,
522 'binary': True,
515 'ops': {NEW_FILENODE: 'new file 100644',
523 'ops': {NEW_FILENODE: 'new file 100644',
516 BIN_FILENODE: 'binary diff hidden'}
524 BIN_FILENODE: 'binary diff hidden'}
517 }),
525 }),
518 ]),
526 ]),
519 ('git',
527 ('git',
520 'git_diff_binary_special_files_2.diff',
528 'git_diff_binary_special_files_2.diff',
521 [('css/Icon\\r', 'A',
529 [('css/Icon\\r', 'A',
522 {'added': 0,
530 {'added': 0,
523 'deleted': 0,
531 'deleted': 0,
524 'binary': True,
532 'binary': True,
525 'ops': {NEW_FILENODE: 'new file 100644', }
533 'ops': {NEW_FILENODE: 'new file 100644', }
526 }),
534 }),
527 ]),
535 ]),
528
536
529 ('svn',
537 ('svn',
530 'svn_diff_binary_add_file.diff',
538 'svn_diff_binary_add_file.diff',
531 [('intl.dll', 'A',
539 [('intl.dll', 'A',
532 {'added': 0,
540 {'added': 0,
533 'deleted': 0,
541 'deleted': 0,
534 'binary': False,
542 'binary': False,
535 'ops': {NEW_FILENODE: 'new file 10644',
543 'ops': {NEW_FILENODE: 'new file 10644',
536 #TODO(Marcink): depends on binary detection on svn patches
544 #TODO(Marcink): depends on binary detection on svn patches
537 # BIN_FILENODE: 'binary diff hidden'
545 # BIN_FILENODE: 'binary diff hidden'
538 }
546 }
539 }),
547 }),
540 ]),
548 ]),
541
549
542 ('svn',
550 ('svn',
543 'svn_diff_multiple_changes.diff',
551 'svn_diff_multiple_changes.diff',
544 [('trunk/doc/images/SettingsOverlay.png', 'M',
552 [('trunk/doc/images/SettingsOverlay.png', 'M',
545 {'added': 0,
553 {'added': 0,
546 'deleted': 0,
554 'deleted': 0,
547 'binary': False,
555 'binary': False,
548 'ops': {MOD_FILENODE: 'modified file',
556 'ops': {MOD_FILENODE: 'modified file',
549 #TODO(Marcink): depends on binary detection on svn patches
557 #TODO(Marcink): depends on binary detection on svn patches
550 # BIN_FILENODE: 'binary diff hidden'
558 # BIN_FILENODE: 'binary diff hidden'
551 }
559 }
552 }),
560 }),
553 ('trunk/doc/source/de/tsvn_ch04.xml', 'M',
561 ('trunk/doc/source/de/tsvn_ch04.xml', 'M',
554 {'added': 89,
562 {'added': 89,
555 'deleted': 34,
563 'deleted': 34,
556 'binary': False,
564 'binary': False,
557 'ops': {MOD_FILENODE: 'modified file'}
565 'ops': {MOD_FILENODE: 'modified file'}
558 }),
566 }),
559 ('trunk/doc/source/en/tsvn_ch04.xml', 'M',
567 ('trunk/doc/source/en/tsvn_ch04.xml', 'M',
560 {'added': 66,
568 {'added': 66,
561 'deleted': 21,
569 'deleted': 21,
562 'binary': False,
570 'binary': False,
563 'ops': {MOD_FILENODE: 'modified file'}
571 'ops': {MOD_FILENODE: 'modified file'}
564 }),
572 }),
565 ('trunk/src/Changelog.txt', 'M',
573 ('trunk/src/Changelog.txt', 'M',
566 {'added': 2,
574 {'added': 2,
567 'deleted': 0,
575 'deleted': 0,
568 'binary': False,
576 'binary': False,
569 'ops': {MOD_FILENODE: 'modified file'}
577 'ops': {MOD_FILENODE: 'modified file'}
570 }),
578 }),
571 ('trunk/src/Resources/TortoiseProcENG.rc', 'M',
579 ('trunk/src/Resources/TortoiseProcENG.rc', 'M',
572 {'added': 19,
580 {'added': 19,
573 'deleted': 13,
581 'deleted': 13,
574 'binary': False,
582 'binary': False,
575 'ops': {MOD_FILENODE: 'modified file'}
583 'ops': {MOD_FILENODE: 'modified file'}
576 }),
584 }),
577 ('trunk/src/TortoiseProc/SetOverlayPage.cpp', 'M',
585 ('trunk/src/TortoiseProc/SetOverlayPage.cpp', 'M',
578 {'added': 16,
586 {'added': 16,
579 'deleted': 1,
587 'deleted': 1,
580 'binary': False,
588 'binary': False,
581 'ops': {MOD_FILENODE: 'modified file'}
589 'ops': {MOD_FILENODE: 'modified file'}
582 }),
590 }),
583 ('trunk/src/TortoiseProc/SetOverlayPage.h', 'M',
591 ('trunk/src/TortoiseProc/SetOverlayPage.h', 'M',
584 {'added': 3,
592 {'added': 3,
585 'deleted': 0,
593 'deleted': 0,
586 'binary': False,
594 'binary': False,
587 'ops': {MOD_FILENODE: 'modified file'}
595 'ops': {MOD_FILENODE: 'modified file'}
588 }),
596 }),
589 ('trunk/src/TortoiseProc/resource.h', 'M',
597 ('trunk/src/TortoiseProc/resource.h', 'M',
590 {'added': 2,
598 {'added': 2,
591 'deleted': 0,
599 'deleted': 0,
592 'binary': False,
600 'binary': False,
593 'ops': {MOD_FILENODE: 'modified file'}
601 'ops': {MOD_FILENODE: 'modified file'}
594 }),
602 }),
595 ('trunk/src/TortoiseShell/ShellCache.h', 'M',
603 ('trunk/src/TortoiseShell/ShellCache.h', 'M',
596 {'added': 50,
604 {'added': 50,
597 'deleted': 1,
605 'deleted': 1,
598 'binary': False,
606 'binary': False,
599 'ops': {MOD_FILENODE: 'modified file'}
607 'ops': {MOD_FILENODE: 'modified file'}
600 }),
608 }),
601 ]),
609 ]),
602
610
603 ]
611 ]
604
612
605 DIFF_FIXTURES_WITH_CONTENT = [
613 DIFF_FIXTURES_WITH_CONTENT = [
606 (
614 (
607 'hg', 'hg_diff_single_file_change_newline.diff',
615 'hg', 'hg_diff_single_file_change_newline.diff',
608 [
616 [
609 (
617 (
610 'file_b', # filename
618 'file_b', # filename
611 'A', # change
619 'A', # change
612 { # stats
620 { # stats
613 'added': 1,
621 'added': 1,
614 'deleted': 0,
622 'deleted': 0,
615 'binary': False,
623 'binary': False,
616 'ops': {NEW_FILENODE: 'new file 100644', }
624 'ops': {NEW_FILENODE: 'new file 100644', }
617 },
625 },
618 '@@ -0,0 +1 @@\n+test_content b\n' # diff
626 '@@ -0,0 +1 @@\n+test_content b\n' # diff
619 ),
627 ),
620 ],
628 ],
621 ),
629 ),
622 (
630 (
623 'hg', 'hg_diff_double_file_change_newline.diff',
631 'hg', 'hg_diff_double_file_change_newline.diff',
624 [
632 [
625 (
633 (
626 'file_b', # filename
634 'file_b', # filename
627 'A', # change
635 'A', # change
628 { # stats
636 { # stats
629 'added': 1,
637 'added': 1,
630 'deleted': 0,
638 'deleted': 0,
631 'binary': False,
639 'binary': False,
632 'ops': {NEW_FILENODE: 'new file 100644', }
640 'ops': {NEW_FILENODE: 'new file 100644', }
633 },
641 },
634 '@@ -0,0 +1 @@\n+test_content b\n' # diff
642 '@@ -0,0 +1 @@\n+test_content b\n' # diff
635 ),
643 ),
636 (
644 (
637 'file_c', # filename
645 'file_c', # filename
638 'A', # change
646 'A', # change
639 { # stats
647 { # stats
640 'added': 1,
648 'added': 1,
641 'deleted': 0,
649 'deleted': 0,
642 'binary': False,
650 'binary': False,
643 'ops': {NEW_FILENODE: 'new file 100644', }
651 'ops': {NEW_FILENODE: 'new file 100644', }
644 },
652 },
645 '@@ -0,0 +1 @@\n+test_content c\n' # diff
653 '@@ -0,0 +1 @@\n+test_content c\n' # diff
646 ),
654 ),
647 ],
655 ],
648 ),
656 ),
649 (
657 (
650 'hg', 'hg_diff_double_file_change_double_newline.diff',
658 'hg', 'hg_diff_double_file_change_double_newline.diff',
651 [
659 [
652 (
660 (
653 'file_b', # filename
661 'file_b', # filename
654 'A', # change
662 'A', # change
655 { # stats
663 { # stats
656 'added': 1,
664 'added': 1,
657 'deleted': 0,
665 'deleted': 0,
658 'binary': False,
666 'binary': False,
659 'ops': {NEW_FILENODE: 'new file 100644', }
667 'ops': {NEW_FILENODE: 'new file 100644', }
660 },
668 },
661 '@@ -0,0 +1 @@\n+test_content b\n\n' # diff
669 '@@ -0,0 +1 @@\n+test_content b\n\n' # diff
662 ),
670 ),
663 (
671 (
664 'file_c', # filename
672 'file_c', # filename
665 'A', # change
673 'A', # change
666 { # stats
674 { # stats
667 'added': 1,
675 'added': 1,
668 'deleted': 0,
676 'deleted': 0,
669 'binary': False,
677 'binary': False,
670 'ops': {NEW_FILENODE: 'new file 100644', }
678 'ops': {NEW_FILENODE: 'new file 100644', }
671 },
679 },
672 '@@ -0,0 +1 @@\n+test_content c\n' # diff
680 '@@ -0,0 +1 @@\n+test_content c\n' # diff
673 ),
681 ),
674 ],
682 ],
675 ),
683 ),
676 (
684 (
677 'hg', 'hg_diff_four_file_change_newline.diff',
685 'hg', 'hg_diff_four_file_change_newline.diff',
678 [
686 [
679 (
687 (
680 'file', # filename
688 'file', # filename
681 'A', # change
689 'A', # change
682 { # stats
690 { # stats
683 'added': 1,
691 'added': 1,
684 'deleted': 0,
692 'deleted': 0,
685 'binary': False,
693 'binary': False,
686 'ops': {NEW_FILENODE: 'new file 100644', }
694 'ops': {NEW_FILENODE: 'new file 100644', }
687 },
695 },
688 '@@ -0,0 +1,1 @@\n+file\n' # diff
696 '@@ -0,0 +1,1 @@\n+file\n' # diff
689 ),
697 ),
690 (
698 (
691 'file2', # filename
699 'file2', # filename
692 'A', # change
700 'A', # change
693 { # stats
701 { # stats
694 'added': 1,
702 'added': 1,
695 'deleted': 0,
703 'deleted': 0,
696 'binary': False,
704 'binary': False,
697 'ops': {NEW_FILENODE: 'new file 100644', }
705 'ops': {NEW_FILENODE: 'new file 100644', }
698 },
706 },
699 '@@ -0,0 +1,1 @@\n+another line\n' # diff
707 '@@ -0,0 +1,1 @@\n+another line\n' # diff
700 ),
708 ),
701 (
709 (
702 'file3', # filename
710 'file3', # filename
703 'A', # change
711 'A', # change
704 { # stats
712 { # stats
705 'added': 1,
713 'added': 1,
706 'deleted': 0,
714 'deleted': 0,
707 'binary': False,
715 'binary': False,
708 'ops': {NEW_FILENODE: 'new file 100644', }
716 'ops': {NEW_FILENODE: 'new file 100644', }
709 },
717 },
710 '@@ -0,0 +1,1 @@\n+newline\n' # diff
718 '@@ -0,0 +1,1 @@\n+newline\n' # diff
711 ),
719 ),
712 (
720 (
713 'file4', # filename
721 'file4', # filename
714 'A', # change
722 'A', # change
715 { # stats
723 { # stats
716 'added': 1,
724 'added': 1,
717 'deleted': 0,
725 'deleted': 0,
718 'binary': False,
726 'binary': False,
719 'ops': {NEW_FILENODE: 'new file 100644', }
727 'ops': {NEW_FILENODE: 'new file 100644', }
720 },
728 },
721 '@@ -0,0 +1,1 @@\n+fil4\n\\ No newline at end of file' # diff
729 '@@ -0,0 +1,1 @@\n+fil4\n\\ No newline at end of file' # diff
722 ),
730 ),
723 ],
731 ],
724 ),
732 ),
725
733
726 ]
734 ]
727
735
728
736
729 diff_class = {
737 diff_class = {
730 'git': GitDiff,
738 'git': GitDiff,
731 'hg': MercurialDiff,
739 'hg': MercurialDiff,
732 'svn': SubversionDiff,
740 'svn': SubversionDiff,
733 }
741 }
734
742
735
743
736 @pytest.fixture(params=DIFF_FIXTURES)
744 @pytest.fixture(params=DIFF_FIXTURES)
737 def diff_fixture(request):
745 def diff_fixture(request):
738 vcs, diff_fixture, expected = request.param
746 vcs, diff_fixture, expected = request.param
739 diff_txt = fixture.load_resource(diff_fixture)
747 diff_txt = fixture.load_resource(diff_fixture)
740 diff = diff_class[vcs](diff_txt)
748 diff = diff_class[vcs](diff_txt)
741 return diff, expected
749 return diff, expected
742
750
743
751
744 def test_diff_lib(diff_fixture):
752 def test_diff_lib(diff_fixture):
745 diff, expected_data = diff_fixture
753 diff, expected_data = diff_fixture
746 diff_proc = DiffProcessor(diff)
754 diff_proc = DiffProcessor(diff)
747 diff_proc_d = diff_proc.prepare()
755 diff_proc_d = diff_proc.prepare()
748 data = [(x['filename'], x['operation'], x['stats']) for x in diff_proc_d]
756 data = [(x['filename'], x['operation'], x['stats']) for x in diff_proc_d]
749 assert expected_data == data
757 assert expected_data == data
750
758
751
759
752 @pytest.fixture(params=DIFF_FIXTURES_WITH_CONTENT)
760 @pytest.fixture(params=DIFF_FIXTURES_WITH_CONTENT)
753 def diff_fixture_w_content(request):
761 def diff_fixture_w_content(request):
754 vcs, diff_fixture, expected = request.param
762 vcs, diff_fixture, expected = request.param
755 diff_txt = fixture.load_resource(diff_fixture)
763 diff_txt = fixture.load_resource(diff_fixture)
756 diff = diff_class[vcs](diff_txt)
764 diff = diff_class[vcs](diff_txt)
757 return diff, expected
765 return diff, expected
758
766
759
767
760 def test_diff_over_limit(request):
768 def test_diff_over_limit(request):
761
769
762 diff_limit = 1024
770 diff_limit = 1024
763 file_limit = 1024
771 file_limit = 1024
764
772
765 raw_diff = fixture.load_resource('large_diff.diff')
773 raw_diff = fixture.load_resource('large_diff.diff')
766 vcs_diff = GitDiff(raw_diff)
774 vcs_diff = GitDiff(raw_diff)
767 diff_processor = DiffProcessor(
775 diff_processor = DiffProcessor(
768 vcs_diff, format='newdiff', diff_limit=diff_limit, file_limit=file_limit,
776 vcs_diff, format='newdiff', diff_limit=diff_limit, file_limit=file_limit,
769 show_full_diff=False)
777 show_full_diff=False)
770
778
771 _parsed = diff_processor.prepare()
779 _parsed = diff_processor.prepare()
772
780
773 commit1 = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
781 commit1 = GitCommit(repository=mock.Mock(), raw_id='abcdef12', idx=1)
774 commit2 = GitCommit(repository=mock.Mock(), raw_id='abcdef34', idx=2)
782 commit2 = GitCommit(repository=mock.Mock(), raw_id='abcdef34', idx=2)
775
783
776 diffset = DiffSet(
784 diffset = DiffSet(
777 repo_name='repo_name',
785 repo_name='repo_name',
778 source_node_getter=lambda *a, **kw: AttributeDict({'commit': commit1}),
786 source_node_getter=lambda *a, **kw: AttributeDict({'commit': commit1}),
779 target_node_getter=lambda *a, **kw: AttributeDict({'commit': commit2})
787 target_node_getter=lambda *a, **kw: AttributeDict({'commit': commit2})
780 )
788 )
781
789
782 diffset = diffset.render_patchset(_parsed, commit1, commit2)
790 diffset = diffset.render_patchset(_parsed, commit1, commit2)
783
791
784 assert len(diffset.files) == 2
792 assert len(diffset.files) == 2
785 assert diffset.limited_diff is True
793 assert diffset.limited_diff is True
786 assert diffset.files[0].patch['filename'] == 'example.go'
794 assert diffset.files[0].patch['filename'] == 'example.go'
787 assert diffset.files[0].limited_diff is True
795 assert diffset.files[0].limited_diff is True
788
796
789 assert diffset.files[1].patch['filename'] == 'README.md'
797 assert diffset.files[1].patch['filename'] == 'README.md'
790 assert diffset.files[1].limited_diff is False
798 assert diffset.files[1].limited_diff is False
791
799
792
800
793 def test_diff_lib_newlines(diff_fixture_w_content):
801 def test_diff_lib_newlines(diff_fixture_w_content):
794 diff, expected_data = diff_fixture_w_content
802 diff, expected_data = diff_fixture_w_content
795 diff_proc = DiffProcessor(diff)
803 diff_proc = DiffProcessor(diff)
796 diff_proc_d = diff_proc.prepare()
804 diff_proc_d = diff_proc.prepare()
797 data = [(x['filename'], x['operation'], x['stats'], x['raw_diff'])
805 data = [(x['filename'], x['operation'], x['stats'], x['raw_diff'])
798 for x in diff_proc_d]
806 for x in diff_proc_d]
799 assert expected_data == data
807 assert expected_data == data
800
808
801
809
802 @pytest.mark.parametrize('input_str', [
810 @pytest.mark.parametrize('input_str', [
803 '',
811 '',
804 '\n',
812 '\n',
805 '\n\n',
813 '\n\n',
806 'First\n+second',
814 'First\n+second',
807 'First\n+second\n',
815 'First\n+second\n',
808
816
809 '\n\n\n Multi \n\n\n',
817 '\n\n\n Multi \n\n\n',
810 '\n\n\n Multi beginning',
818 '\n\n\n Multi beginning',
811 'Multi end \n\n\n',
819 'Multi end \n\n\n',
812 'Multi end',
820 'Multi end',
813 '@@ -0,0 +1 @@\n+test_content \n\n b\n'
821 '@@ -0,0 +1 @@\n+test_content \n\n b\n'
814 ], ids=no_newline_id_generator)
822 ], ids=no_newline_id_generator)
815 def test_splitlines(input_str):
823 def test_splitlines(input_str):
816 result = DiffProcessor.diff_splitter(input_str)
824 result = DiffProcessor.diff_splitter(input_str)
817 assert list(result) == input_str.splitlines(True)
825 assert list(result) == input_str.splitlines(True)
General Comments 0
You need to be logged in to leave comments. Login now