docs: add Albert to the credits
[git-cola.git] / test / diffparse_test.py
blobb4b2b7aa3658baffc57cb010d121ca2b061b9d7c
1 """Tests for the diffparse module"""
2 # pylint: disable=redefined-outer-name
4 import pytest
6 from cola import core
7 from cola import diffparse
9 from . import helper
12 class DiffLinesTestData:
13 """Test data used by DiffLines tests"""
15 def __init__(self):
16 self.parser = diffparse.DiffLines()
17 fixture_path = helper.fixture('diff.txt')
18 self.text = core.read(fixture_path)
21 @pytest.fixture
22 def difflines_data():
23 """Return test data for diffparse.DiffLines tests"""
24 return DiffLinesTestData()
27 def test_diff():
28 fixture_path = helper.fixture('diff.txt')
29 patch = diffparse.Patch.parse('cola/diffparse.py', core.read(fixture_path))
30 hunks = patch.hunks
32 assert len(hunks) == 3
33 assert len(hunks[0].lines) == 23
34 assert hunks[0].lines[0] == '@@ -6,10 +6,21 @@ from cola import gitcmds\n'
35 assert hunks[0].lines[1] == ' from cola import gitcfg\n'
36 assert hunks[0].lines[2] == ' \n'
37 assert hunks[0].lines[3] == ' \n'
38 assert hunks[0].lines[4] == '+class DiffSource(object):\n'
39 assert hunks[0].lines[-1] == (
40 r" self._header_start_re = re.compile('^@@ -(\d+)"
41 r" \+(\d+),(\d+) @@.*')"
42 '\n'
44 assert len(hunks[1].lines) == 18
45 assert hunks[1].lines[0] == '@@ -29,13 +40,11 @@ class DiffParser(object):\n'
46 assert hunks[1].lines[1] == ' self.diff_sel = []\n'
47 assert hunks[1].lines[2] == ' self.selected = []\n'
48 assert hunks[1].lines[3] == ' self.filename = filename\n'
49 assert hunks[1].lines[4] == (
50 '+ self.diff_source = diff_source or DiffSource()\n'
52 assert hunks[1].lines[-1] == ' self.header = header\n'
54 assert len(hunks[2].lines) == 16
55 assert hunks[2].lines[0] == '@@ -43,11 +52,10 @@ class DiffParser(object):\n'
56 assert hunks[2].lines[-1] == (
57 ' """Writes a new diff corresponding to the user\'s' ' selection."""\n'
61 def test_diff_at_start():
62 fixture_path = helper.fixture('diff-start.txt')
63 patch = diffparse.Patch.parse('foo bar/a', core.read(fixture_path))
64 hunks = patch.hunks
66 assert hunks[0].lines[0] == '@@ -1 +1,4 @@\n'
67 assert hunks[-1].lines[-1] == '+c\n'
68 assert hunks[0].old_start == 1
69 assert hunks[0].old_count == 1
70 assert hunks[0].new_start == 1
71 assert hunks[0].new_count == 4
72 assert patch.extract_subset(1, 3).as_text() == (
73 '--- a/foo bar/a\n' '+++ b/foo bar/a\n' '@@ -1 +1,3 @@\n' ' bar\n' '+a\n' '+b\n'
75 assert patch.extract_subset(0, 4).as_text() == (
76 '--- a/foo bar/a\n'
77 '+++ b/foo bar/a\n'
78 '@@ -1 +1,4 @@\n'
79 ' bar\n'
80 '+a\n'
81 '+b\n'
82 '+c\n'
86 def test_diff_at_end():
87 fixture_path = helper.fixture('diff-end.txt')
88 patch = diffparse.Patch.parse('rijndael.js', core.read(fixture_path))
89 hunks = patch.hunks
91 assert hunks[0].lines[0] == '@@ -1,39 +1 @@\n'
92 assert hunks[-1].lines[-1] == (
93 "+module.exports = require('./build/Release/rijndael');\n"
95 assert hunks[0].old_start == 1
96 assert hunks[0].old_count == 39
97 assert hunks[0].new_start == 1
98 assert hunks[0].new_count == 1
101 def test_diff_that_empties_file():
102 fixture_path = helper.fixture('diff-empty.txt')
103 patch = diffparse.Patch.parse('filename', core.read(fixture_path))
104 hunks = patch.hunks
106 assert hunks[0].lines[0] == '@@ -1,2 +0,0 @@\n'
107 assert hunks[-1].lines[-1] == '-second\n'
108 assert hunks[0].old_start == 1
109 assert hunks[0].old_count == 2
110 assert hunks[0].new_start == 0
111 assert hunks[0].new_count == 0
112 assert patch.extract_subset(1, 1).as_text() == (
113 '--- a/filename\n' '+++ b/filename\n' '@@ -1,2 +1 @@\n' '-first\n' ' second\n'
115 assert patch.extract_subset(0, 2).as_text() == (
116 '--- a/filename\n' '+++ b/filename\n' '@@ -1,2 +0,0 @@\n' '-first\n' '-second\n'
120 def test_diff_file_removal():
121 diff_text = """\
122 deleted file mode 100755
123 @@ -1,1 +0,0 @@
124 -#!/bin/sh
126 patch = diffparse.Patch.parse('deleted.txt', diff_text)
128 expect = 1
129 actual = len(patch.hunks)
130 assert expect == actual
132 # Selecting the first two lines generate no diff
133 expect = ''
134 actual = patch.extract_subset(0, 1).as_text()
135 assert expect == actual
137 # Selecting the last line should generate a line removal
138 expect = """\
139 --- a/deleted.txt
140 +++ b/deleted.txt
141 @@ -1 +0,0 @@
142 -#!/bin/sh
144 actual = patch.extract_subset(1, 2).as_text()
145 assert expect == actual
147 # All three lines should map to the same hunk diff
148 actual = patch.extract_hunk(0).as_text()
149 assert expect == actual
151 actual = patch.extract_hunk(1).as_text()
152 assert expect == actual
154 actual = patch.extract_hunk(2).as_text()
155 assert expect == actual
158 def test_basic_diff_line_count(difflines_data):
159 """Verify the basic line counts"""
160 lines = difflines_data.parser.parse(difflines_data.text)
161 expect = len(difflines_data.text.splitlines())
162 actual = len(lines)
163 assert expect == actual
166 def test_diff_line_count_ranges(difflines_data):
167 parser = difflines_data.parser
168 lines = parser.parse(difflines_data.text)
170 # Diff header
171 line = 0
172 count = 1
173 assert lines[line][0] == parser.DASH
174 assert lines[line][1] == parser.DASH
175 line += count
177 # 3 lines of context
178 count = 3
179 current_old = 6
180 current_new = 6
181 for i in range(count):
182 assert lines[line + i][0] == current_old + i
183 assert lines[line + i][1] == current_new + i
184 line += count
185 current_old += count
186 current_new += count
188 # 10 lines of new text
189 count = 10
190 for i in range(count):
191 assert lines[line + i][0] == parser.EMPTY
192 assert lines[line + i][1] == current_new + i
194 line += count
195 current_new += count
197 # 3 more lines of context
198 count = 3
199 for i in range(count):
200 assert lines[line + i][0] == current_old + i
201 assert lines[line + i][1] == current_new + i
202 line += count
203 current_new += count
204 current_old += count
206 # 1 line of removal
207 count = 1
208 for i in range(count):
209 assert lines[line + i][0] == current_old + i
210 assert lines[line + i][1] == parser.EMPTY
211 line += count
212 current_old += count
214 # 2 lines of addition
215 count = 2
216 for i in range(count):
217 assert lines[line + i][0] == parser.EMPTY
218 assert lines[line + i][1] == current_new + i
219 line += count
220 current_new += count
222 # 3 more lines of context
223 count = 3
224 for i in range(count):
225 assert lines[line + i][0] == current_old + i
226 assert lines[line + i][1] == current_new + i
227 line += count
228 current_new += count
229 current_old += count
231 # 1 line of header
232 count = 1
233 for i in range(count):
234 assert lines[line + i][0] == parser.DASH
235 assert lines[line + i][1] == parser.DASH
236 line += count
238 # 3 more lines of context
239 current_old = 29
240 current_new = 40
241 count = 3
242 for i in range(count):
243 assert lines[line + i][0] == current_old + i
244 assert lines[line + i][1] == current_new + i
245 line += count
246 current_new += count
247 current_old += count
249 expect_max_old = 53
250 assert expect_max_old == parser.old.max_value
252 expect_max_new = 61
253 assert expect_max_new == parser.new.max_value
255 assert parser.digits() == 2
258 def test_diff_line_for_merge(difflines_data):
259 """Verify the basic line counts"""
260 text = """@@@ -1,23 -1,33 +1,75 @@@
261 ++<<<<<<< upstream
265 parser = difflines_data.parser
266 lines = parser.parse(text)
267 assert len(lines) == 4
268 assert len(lines[0]) == 3
269 assert len(lines[1]) == 3
270 assert len(lines[2]) == 3
271 assert len(lines[3]) == 3
273 assert lines[0][0] == parser.DASH
274 assert lines[0][1] == parser.DASH
275 assert lines[0][2] == parser.DASH
277 assert lines[1][0] == parser.EMPTY
278 assert lines[1][1] == parser.EMPTY
279 assert lines[1][2] == 1
281 assert lines[2][0] == 1
282 assert lines[2][1] == parser.EMPTY
283 assert lines[2][2] == 2
285 assert lines[3][0] == 2
286 assert lines[3][1] == parser.EMPTY
287 assert lines[3][2] == 3
290 def test_diff_line_digits(difflines_data):
291 parser = difflines_data.parser
293 text = """@@ -1,99 +1,99 @@"""
294 parser.parse(text)
295 assert parser.digits() == 2
297 text = """@@ -2,99 +2,99 @@"""
298 parser.parse(text)
299 assert parser.digits() == 3
302 def test_format_basic():
303 fmt = diffparse.FormatDigits()
304 fmt.set_digits(2)
306 expect = '01 99'
307 actual = fmt.value(1, 99)
308 assert expect == actual
311 def test_format_reuse():
312 fmt = diffparse.FormatDigits()
314 fmt.set_digits(3)
315 expect = '001 099'
316 actual = fmt.value(1, 99)
317 assert expect == actual
319 fmt.set_digits(4)
320 expect = '0001 0099'
321 actual = fmt.value(1, 99)
322 assert expect == actual
325 def test_format_special_values():
326 fmt = diffparse.FormatDigits(dash='-')
327 fmt.set_digits(3)
329 expect = ' 099'
330 actual = fmt.value(fmt.EMPTY, 99)
331 assert expect == actual
333 expect = '001 '
334 actual = fmt.value(1, fmt.EMPTY)
335 assert expect == actual
337 expect = ' '
338 actual = fmt.value(fmt.EMPTY, fmt.EMPTY)
339 assert expect == actual
341 expect = '--- 001'
342 actual = fmt.value(fmt.DASH, 1)
343 assert expect == actual
345 expect = '099 ---'
346 actual = fmt.value(99, fmt.DASH)
347 assert expect == actual
349 expect = '--- ---'
350 actual = fmt.value(fmt.DASH, fmt.DASH)
351 assert expect == actual
353 expect = ' ---'
354 actual = fmt.value(fmt.EMPTY, fmt.DASH)
355 assert expect == actual
357 expect = '--- '
358 actual = fmt.value(fmt.DASH, fmt.EMPTY)
359 assert expect == actual
362 def test_parse_range_str():
363 start, count = diffparse.parse_range_str('1,2')
364 assert start == 1
365 assert count == 2
368 def test_parse_range_str_single_line():
369 start, count = diffparse.parse_range_str('2')
370 assert start == 2
371 assert count == 1
374 def test_parse_range_str_empty():
375 start, count = diffparse.parse_range_str('0,0')
376 assert start == 0
377 assert count == 0