CHANGES: mention the improvements from #1205 and #1206
[git-cola.git] / test / diffparse_test.py
bloba338c6fa1373276cbc53a507df7f447ea1364387
1 """Tests for the diffparse module"""
2 # pylint: disable=redefined-outer-name
3 from __future__ import absolute_import, division, print_function, unicode_literals
5 import pytest
7 from cola import core
8 from cola import diffparse
10 from . import helper
13 class DiffLinesTestData(object):
14 """Test data used by DiffLines tests"""
16 def __init__(self):
17 self.parser = diffparse.DiffLines()
18 fixture_path = helper.fixture('diff.txt')
19 self.text = core.read(fixture_path)
22 @pytest.fixture
23 def difflines_data():
24 """Return test data for diffparse.DiffLines tests"""
25 return DiffLinesTestData()
28 def test_diff():
29 fixture_path = helper.fixture('diff.txt')
30 parser = diffparse.DiffParser('cola/diffparse.py', core.read(fixture_path))
31 hunks = parser.hunks
33 assert len(hunks) == 3
34 assert hunks[0].first_line_idx == 0
35 assert len(hunks[0].lines) == 23
36 assert hunks[0].lines[0] == '@@ -6,10 +6,21 @@ from cola import gitcmds\n'
37 assert hunks[0].lines[1] == ' from cola import gitcfg\n'
38 assert hunks[0].lines[2] == ' \n'
39 assert hunks[0].lines[3] == ' \n'
40 assert hunks[0].lines[4] == '+class DiffSource(object):\n'
41 assert hunks[0].lines[-1] == (
42 r" self._header_start_re = re.compile('^@@ -(\d+)"
43 r" \+(\d+),(\d+) @@.*')"
44 '\n'
46 assert hunks[1].first_line_idx == 23
47 assert len(hunks[1].lines) == 18
48 assert hunks[1].lines[0] == '@@ -29,13 +40,11 @@ class DiffParser(object):\n'
49 assert hunks[1].lines[1] == ' self.diff_sel = []\n'
50 assert hunks[1].lines[2] == ' self.selected = []\n'
51 assert hunks[1].lines[3] == ' self.filename = filename\n'
52 assert hunks[1].lines[4] == (
53 '+ self.diff_source = diff_source or DiffSource()\n'
55 assert hunks[1].lines[-1] == ' self.header = header\n'
57 assert hunks[2].first_line_idx == 41
58 assert len(hunks[2].lines) == 16
59 assert hunks[2].lines[0] == '@@ -43,11 +52,10 @@ class DiffParser(object):\n'
60 assert hunks[2].lines[-1] == (
61 ' """Writes a new diff corresponding to the user\'s'
62 ' selection."""\n'
66 def test_diff_at_start():
67 fixture_path = helper.fixture('diff-start.txt')
68 parser = diffparse.DiffParser('foo bar/a', core.read(fixture_path))
69 hunks = parser.hunks
71 assert hunks[0].lines[0] == '@@ -1 +1,4 @@\n'
72 assert hunks[-1].lines[-1] == '+c\n'
73 assert hunks[0].old_start == 1
74 assert hunks[0].old_count == 1
75 assert hunks[0].new_start == 1
76 assert hunks[0].new_count == 4
77 assert parser.generate_patch(1, 3) == (
78 '--- a/foo bar/a\n'
79 '+++ b/foo bar/a\n'
80 '@@ -1 +1,3 @@\n'
81 ' bar\n'
82 '+a\n'
83 '+b\n'
85 assert parser.generate_patch(0, 4) == (
86 '--- a/foo bar/a\n'
87 '+++ b/foo bar/a\n'
88 '@@ -1 +1,4 @@\n'
89 ' bar\n'
90 '+a\n'
91 '+b\n'
92 '+c\n'
96 def test_diff_at_end():
97 fixture_path = helper.fixture('diff-end.txt')
98 parser = diffparse.DiffParser('rijndael.js', core.read(fixture_path))
99 hunks = parser.hunks
101 assert hunks[0].lines[0] == '@@ -1,39 +1 @@\n'
102 assert hunks[-1].lines[-1] == (
103 "+module.exports = require('./build/Release/rijndael');\n"
105 assert hunks[0].old_start == 1
106 assert hunks[0].old_count == 39
107 assert hunks[0].new_start == 1
108 assert hunks[0].new_count == 1
111 def test_diff_that_empties_file():
112 fixture_path = helper.fixture('diff-empty.txt')
113 parser = diffparse.DiffParser('filename', core.read(fixture_path))
114 hunks = parser.hunks
116 assert hunks[0].lines[0] == '@@ -1,2 +0,0 @@\n'
117 assert hunks[-1].lines[-1] == '-second\n'
118 assert hunks[0].old_start == 1
119 assert hunks[0].old_count == 2
120 assert hunks[0].new_start == 0
121 assert hunks[0].new_count == 0
122 assert parser.generate_patch(1, 1) == (
123 '--- a/filename\n'
124 '+++ b/filename\n'
125 '@@ -1,2 +1 @@\n'
126 '-first\n'
127 ' second\n'
129 assert parser.generate_patch(0, 2) == (
130 '--- a/filename\n'
131 '+++ b/filename\n'
132 '@@ -1,2 +0,0 @@\n'
133 '-first\n'
134 '-second\n'
138 def test_diff_file_removal():
139 diff_text = """\
140 deleted file mode 100755
141 @@ -1,1 +0,0 @@
142 -#!/bin/sh
144 parser = diffparse.DiffParser('deleted.txt', diff_text)
146 expect = 1
147 actual = len(parser.hunks)
148 assert expect == actual
150 # Selecting the first two lines generate no diff
151 expect = None
152 actual = parser.generate_patch(0, 1)
153 assert expect == actual
155 # Selecting the last line should generate a line removal
156 expect = """\
157 --- a/deleted.txt
158 +++ b/deleted.txt
159 @@ -1 +0,0 @@
160 -#!/bin/sh
162 actual = parser.generate_patch(1, 2)
163 assert expect == actual
165 # All three lines should map to the same hunk diff
166 actual = parser.generate_hunk_patch(0)
167 assert expect == actual
169 actual = parser.generate_hunk_patch(1)
170 assert expect == actual
172 actual = parser.generate_hunk_patch(2)
173 assert expect == actual
176 def test_basic_diff_line_count(difflines_data):
177 """Verify the basic line counts"""
178 lines = difflines_data.parser.parse(difflines_data.text)
179 expect = len(difflines_data.text.splitlines())
180 actual = len(lines)
181 assert expect == actual
184 def test_diff_line_count_ranges(difflines_data):
185 parser = difflines_data.parser
186 lines = parser.parse(difflines_data.text)
188 # Diff header
189 line = 0
190 count = 1
191 assert lines[line][0] == parser.DASH
192 assert lines[line][1] == parser.DASH
193 line += count
195 # 3 lines of context
196 count = 3
197 current_old = 6
198 current_new = 6
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_old += count
204 current_new += count
206 # 10 lines of new text
207 count = 10
208 for i in range(count):
209 assert lines[line + i][0] == parser.EMPTY
210 assert lines[line + i][1] == current_new + i
212 line += count
213 current_new += count
215 # 3 more lines of context
216 count = 3
217 for i in range(count):
218 assert lines[line + i][0] == current_old + i
219 assert lines[line + i][1] == current_new + i
220 line += count
221 current_new += count
222 current_old += count
224 # 1 line of removal
225 count = 1
226 for i in range(count):
227 assert lines[line + i][0] == current_old + i
228 assert lines[line + i][1] == parser.EMPTY
229 line += count
230 current_old += count
232 # 2 lines of addition
233 count = 2
234 for i in range(count):
235 assert lines[line + i][0] == parser.EMPTY
236 assert lines[line + i][1] == current_new + i
237 line += count
238 current_new += count
240 # 3 more lines of context
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 # 1 line of header
250 count = 1
251 for i in range(count):
252 assert lines[line + i][0] == parser.DASH
253 assert lines[line + i][1] == parser.DASH
254 line += count
256 # 3 more lines of context
257 current_old = 29
258 current_new = 40
259 count = 3
260 for i in range(count):
261 assert lines[line + i][0] == current_old + i
262 assert lines[line + i][1] == current_new + i
263 line += count
264 current_new += count
265 current_old += count
267 expect_max_old = 54
268 assert expect_max_old == parser.old.max_value
270 expect_max_new = 62
271 assert expect_max_new == parser.new.max_value
273 assert parser.digits() == 2
276 def test_diff_line_for_merge(difflines_data):
277 """Verify the basic line counts"""
278 text = """@@@ -1,23 -1,33 +1,75 @@@
279 ++<<<<<<< upstream
283 parser = difflines_data.parser
284 lines = parser.parse(text)
285 assert len(lines) == 4
286 assert len(lines[0]) == 3
287 assert len(lines[1]) == 3
288 assert len(lines[2]) == 3
289 assert len(lines[3]) == 3
291 assert lines[0][0] == parser.DASH
292 assert lines[0][1] == parser.DASH
293 assert lines[0][2] == parser.DASH
295 assert lines[1][0] == parser.EMPTY
296 assert lines[1][1] == parser.EMPTY
297 assert lines[1][2] == 1
299 assert lines[2][0] == 1
300 assert lines[2][1] == parser.EMPTY
301 assert lines[2][2] == 2
303 assert lines[3][0] == 2
304 assert lines[3][1] == parser.EMPTY
305 assert lines[3][2] == 3
308 def test_format_basic():
309 fmt = diffparse.FormatDigits()
310 fmt.set_digits(2)
312 expect = '01 99'
313 actual = fmt.value(1, 99)
314 assert expect == actual
317 def test_format_reuse():
318 fmt = diffparse.FormatDigits()
320 fmt.set_digits(3)
321 expect = '001 099'
322 actual = fmt.value(1, 99)
323 assert expect == actual
325 fmt.set_digits(4)
326 expect = '0001 0099'
327 actual = fmt.value(1, 99)
328 assert expect == actual
331 def test_format_special_values():
332 fmt = diffparse.FormatDigits(dash='-')
333 fmt.set_digits(3)
335 expect = ' 099'
336 actual = fmt.value(fmt.EMPTY, 99)
337 assert expect == actual
339 expect = '001 '
340 actual = fmt.value(1, fmt.EMPTY)
341 assert expect == actual
343 expect = ' '
344 actual = fmt.value(fmt.EMPTY, fmt.EMPTY)
345 assert expect == actual
347 expect = '--- 001'
348 actual = fmt.value(fmt.DASH, 1)
349 assert expect == actual
351 expect = '099 ---'
352 actual = fmt.value(99, fmt.DASH)
353 assert expect == actual
355 expect = '--- ---'
356 actual = fmt.value(fmt.DASH, fmt.DASH)
357 assert expect == actual
359 expect = ' ---'
360 actual = fmt.value(fmt.EMPTY, fmt.DASH)
361 assert expect == actual
363 expect = '--- '
364 actual = fmt.value(fmt.DASH, fmt.EMPTY)
365 assert expect == actual
368 def test_parse_range_str():
369 start, count = diffparse.parse_range_str('1,2')
370 assert start == 1
371 assert count == 2
374 def test_parse_range_str_single_line():
375 start, count = diffparse.parse_range_str('2')
376 assert start == 2
377 assert count == 1
380 def test_parse_range_str_empty():
381 start, count = diffparse.parse_range_str('0,0')
382 assert start == 0
383 assert count == 0