fetch: add ability to fetch into a remote tracking branch
[git-cola.git] / test / diffparse_test.py
blob685d621a813a842d049fd345bebd97b85ee4da3f
1 """Tests for the diffparse module"""
2 import pytest
4 from cola import core
5 from cola import diffparse
7 from . import helper
10 class DiffLinesTestData:
11 """Test data used by DiffLines tests"""
13 def __init__(self):
14 self.parser = diffparse.DiffLines()
15 fixture_path = helper.fixture('diff.txt')
16 self.text = core.read(fixture_path)
19 @pytest.fixture
20 def difflines_data():
21 """Return test data for diffparse.DiffLines tests"""
22 return DiffLinesTestData()
25 def test_diff():
26 fixture_path = helper.fixture('diff.txt')
27 patch = diffparse.Patch.parse('cola/diffparse.py', core.read(fixture_path))
28 hunks = patch.hunks
30 assert len(hunks) == 3
31 assert len(hunks[0].lines) == 23
32 assert hunks[0].lines[0] == '@@ -6,10 +6,21 @@ from cola import gitcmds\n'
33 assert hunks[0].lines[1] == ' from cola import gitcfg\n'
34 assert hunks[0].lines[2] == ' \n'
35 assert hunks[0].lines[3] == ' \n'
36 assert hunks[0].lines[4] == '+class DiffSource(object):\n'
37 assert hunks[0].lines[-1] == (
38 r" self._header_start_re = re.compile('^@@ -(\d+)"
39 r" \+(\d+),(\d+) @@.*')"
40 '\n'
42 assert len(hunks[1].lines) == 18
43 assert hunks[1].lines[0] == '@@ -29,13 +40,11 @@ class DiffParser(object):\n'
44 assert hunks[1].lines[1] == ' self.diff_sel = []\n'
45 assert hunks[1].lines[2] == ' self.selected = []\n'
46 assert hunks[1].lines[3] == ' self.filename = filename\n'
47 assert hunks[1].lines[4] == (
48 '+ self.diff_source = diff_source or DiffSource()\n'
50 assert hunks[1].lines[-1] == ' self.header = header\n'
52 assert len(hunks[2].lines) == 16
53 assert hunks[2].lines[0] == '@@ -43,11 +52,10 @@ class DiffParser(object):\n'
54 assert hunks[2].lines[-1] == (
55 ' """Writes a new diff corresponding to the user\'s' ' selection."""\n'
59 def test_diff_at_start():
60 fixture_path = helper.fixture('diff-start.txt')
61 patch = diffparse.Patch.parse('foo bar/a', core.read(fixture_path))
62 hunks = patch.hunks
64 assert hunks[0].lines[0] == '@@ -1 +1,4 @@\n'
65 assert hunks[-1].lines[-1] == '+c\n'
66 assert hunks[0].old_start == 1
67 assert hunks[0].old_count == 1
68 assert hunks[0].new_start == 1
69 assert hunks[0].new_count == 4
70 assert patch.extract_subset(1, 3).as_text() == (
71 '--- a/foo bar/a\n' '+++ b/foo bar/a\n' '@@ -1 +1,3 @@\n' ' bar\n' '+a\n' '+b\n'
73 assert patch.extract_subset(0, 4).as_text() == (
74 '--- a/foo bar/a\n'
75 '+++ b/foo bar/a\n'
76 '@@ -1 +1,4 @@\n'
77 ' bar\n'
78 '+a\n'
79 '+b\n'
80 '+c\n'
84 def test_diff_at_end():
85 fixture_path = helper.fixture('diff-end.txt')
86 patch = diffparse.Patch.parse('rijndael.js', core.read(fixture_path))
87 hunks = patch.hunks
89 assert hunks[0].lines[0] == '@@ -1,39 +1 @@\n'
90 assert hunks[-1].lines[-1] == (
91 "+module.exports = require('./build/Release/rijndael');\n"
93 assert hunks[0].old_start == 1
94 assert hunks[0].old_count == 39
95 assert hunks[0].new_start == 1
96 assert hunks[0].new_count == 1
99 def test_diff_that_empties_file():
100 fixture_path = helper.fixture('diff-empty.txt')
101 patch = diffparse.Patch.parse('filename', core.read(fixture_path))
102 hunks = patch.hunks
104 assert hunks[0].lines[0] == '@@ -1,2 +0,0 @@\n'
105 assert hunks[-1].lines[-1] == '-second\n'
106 assert hunks[0].old_start == 1
107 assert hunks[0].old_count == 2
108 assert hunks[0].new_start == 0
109 assert hunks[0].new_count == 0
110 assert patch.extract_subset(1, 1).as_text() == (
111 '--- a/filename\n' '+++ b/filename\n' '@@ -1,2 +1 @@\n' '-first\n' ' second\n'
113 assert patch.extract_subset(0, 2).as_text() == (
114 '--- a/filename\n' '+++ b/filename\n' '@@ -1,2 +0,0 @@\n' '-first\n' '-second\n'
118 def test_diff_file_removal():
119 diff_text = """\
120 deleted file mode 100755
121 @@ -1,1 +0,0 @@
122 -#!/bin/sh
124 patch = diffparse.Patch.parse('deleted.txt', diff_text)
126 expect = 1
127 actual = len(patch.hunks)
128 assert expect == actual
130 # Selecting the first two lines generate no diff
131 expect = ''
132 actual = patch.extract_subset(0, 1).as_text()
133 assert expect == actual
135 # Selecting the last line should generate a line removal
136 expect = """\
137 --- a/deleted.txt
138 +++ b/deleted.txt
139 @@ -1 +0,0 @@
140 -#!/bin/sh
142 actual = patch.extract_subset(1, 2).as_text()
143 assert expect == actual
145 # All three lines should map to the same hunk diff
146 actual = patch.extract_hunk(0).as_text()
147 assert expect == actual
149 actual = patch.extract_hunk(1).as_text()
150 assert expect == actual
152 actual = patch.extract_hunk(2).as_text()
153 assert expect == actual
156 def test_basic_diff_line_count(difflines_data):
157 """Verify the basic line counts"""
158 lines = difflines_data.parser.parse(difflines_data.text)
159 expect = len(difflines_data.text.splitlines())
160 actual = len(lines)
161 assert expect == actual
164 def test_diff_line_count_ranges(difflines_data):
165 parser = difflines_data.parser
166 lines = parser.parse(difflines_data.text)
168 # Diff header
169 line = 0
170 count = 1
171 assert lines[line][0] == parser.DASH
172 assert lines[line][1] == parser.DASH
173 line += count
175 # 3 lines of context
176 count = 3
177 current_old = 6
178 current_new = 6
179 for i in range(count):
180 assert lines[line + i][0] == current_old + i
181 assert lines[line + i][1] == current_new + i
182 line += count
183 current_old += count
184 current_new += count
186 # 10 lines of new text
187 count = 10
188 for i in range(count):
189 assert lines[line + i][0] == parser.EMPTY
190 assert lines[line + i][1] == current_new + i
192 line += count
193 current_new += count
195 # 3 more lines of context
196 count = 3
197 for i in range(count):
198 assert lines[line + i][0] == current_old + i
199 assert lines[line + i][1] == current_new + i
200 line += count
201 current_new += count
202 current_old += count
204 # 1 line of removal
205 count = 1
206 for i in range(count):
207 assert lines[line + i][0] == current_old + i
208 assert lines[line + i][1] == parser.EMPTY
209 line += count
210 current_old += count
212 # 2 lines of addition
213 count = 2
214 for i in range(count):
215 assert lines[line + i][0] == parser.EMPTY
216 assert lines[line + i][1] == current_new + i
217 line += count
218 current_new += count
220 # 3 more lines of context
221 count = 3
222 for i in range(count):
223 assert lines[line + i][0] == current_old + i
224 assert lines[line + i][1] == current_new + i
225 line += count
226 current_new += count
227 current_old += count
229 # 1 line of header
230 count = 1
231 for i in range(count):
232 assert lines[line + i][0] == parser.DASH
233 assert lines[line + i][1] == parser.DASH
234 line += count
236 # 3 more lines of context
237 current_old = 29
238 current_new = 40
239 count = 3
240 for i in range(count):
241 assert lines[line + i][0] == current_old + i
242 assert lines[line + i][1] == current_new + i
243 line += count
244 current_new += count
245 current_old += count
247 expect_max_old = 53
248 assert expect_max_old == parser.old.max_value
250 expect_max_new = 61
251 assert expect_max_new == parser.new.max_value
253 assert parser.digits() == 2
256 def test_diff_line_for_merge(difflines_data):
257 """Verify the basic line counts"""
258 text = """@@@ -1,23 -1,33 +1,75 @@@
259 ++<<<<<<< upstream
263 parser = difflines_data.parser
264 lines = parser.parse(text)
265 assert len(lines) == 4
266 assert len(lines[0]) == 3
267 assert len(lines[1]) == 3
268 assert len(lines[2]) == 3
269 assert len(lines[3]) == 3
271 assert lines[0][0] == parser.DASH
272 assert lines[0][1] == parser.DASH
273 assert lines[0][2] == parser.DASH
275 assert lines[1][0] == parser.EMPTY
276 assert lines[1][1] == parser.EMPTY
277 assert lines[1][2] == 1
279 assert lines[2][0] == 1
280 assert lines[2][1] == parser.EMPTY
281 assert lines[2][2] == 2
283 assert lines[3][0] == 2
284 assert lines[3][1] == parser.EMPTY
285 assert lines[3][2] == 3
288 def test_diff_line_digits(difflines_data):
289 parser = difflines_data.parser
291 text = """@@ -1,99 +1,99 @@"""
292 parser.parse(text)
293 assert parser.digits() == 2
295 text = """@@ -2,99 +2,99 @@"""
296 parser.parse(text)
297 assert parser.digits() == 3
300 def test_format_basic():
301 fmt = diffparse.FormatDigits()
302 fmt.set_digits(2)
304 expect = '01 99'
305 actual = fmt.value(1, 99)
306 assert expect == actual
309 def test_format_reuse():
310 fmt = diffparse.FormatDigits()
312 fmt.set_digits(3)
313 expect = '001 099'
314 actual = fmt.value(1, 99)
315 assert expect == actual
317 fmt.set_digits(4)
318 expect = '0001 0099'
319 actual = fmt.value(1, 99)
320 assert expect == actual
323 def test_format_special_values():
324 fmt = diffparse.FormatDigits(dash='-')
325 fmt.set_digits(3)
327 expect = ' 099'
328 actual = fmt.value(fmt.EMPTY, 99)
329 assert expect == actual
331 expect = '001 '
332 actual = fmt.value(1, fmt.EMPTY)
333 assert expect == actual
335 expect = ' '
336 actual = fmt.value(fmt.EMPTY, fmt.EMPTY)
337 assert expect == actual
339 expect = '--- 001'
340 actual = fmt.value(fmt.DASH, 1)
341 assert expect == actual
343 expect = '099 ---'
344 actual = fmt.value(99, fmt.DASH)
345 assert expect == actual
347 expect = '--- ---'
348 actual = fmt.value(fmt.DASH, fmt.DASH)
349 assert expect == actual
351 expect = ' ---'
352 actual = fmt.value(fmt.EMPTY, fmt.DASH)
353 assert expect == actual
355 expect = '--- '
356 actual = fmt.value(fmt.DASH, fmt.EMPTY)
357 assert expect == actual
360 def test_parse_range_str():
361 start, count = diffparse.parse_range_str('1,2')
362 assert start == 1
363 assert count == 2
366 def test_parse_range_str_single_line():
367 start, count = diffparse.parse_range_str('2')
368 assert start == 2
369 assert count == 1
372 def test_parse_range_str_empty():
373 start, count = diffparse.parse_range_str('0,0')
374 assert start == 0
375 assert count == 0