13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from bzrlib.tests import TestCaseInTempDir, TestCase
19
from bzrlib.merge3 import Merge3
22
20
from bzrlib.errors import CantReprocessAndShowBase, BinaryFile
24
22
def split_lines(t):
31
29
TZU = split_lines(""" The Nameless is the origin of Heaven and Earth;
32
30
The named is the mother of all things.
34
32
Therefore let there always be non-being,
35
33
so we may see their subtlety,
36
34
And let there always be being,
61
59
The name that can be named is not the eternal name.
62
60
The Nameless is the origin of Heaven and Earth;
63
61
The named is the mother of all things.
65
63
Therefore let there always be non-being,
66
64
so we may see their subtlety,
67
65
And let there always be being,
87
85
they have different names.
91
89
-- The Way of Lao-Tzu, tr. Wing-tsit Chan
96
class TestMerge3(tests.TestCase):
94
class TestMerge3(TestCase):
98
96
def test_no_changes(self):
99
97
"""No conflicts because nothing changed"""
100
m3 = merge3.Merge3(['aaa', 'bbb'],
98
m3 = Merge3(['aaa', 'bbb'],
104
102
self.assertEquals(m3.find_unconflicted(),
153
151
def test_no_conflicts(self):
154
152
"""No conflicts because only one side changed"""
155
m3 = merge3.Merge3(['aaa', 'bbb'],
156
['aaa', '111', 'bbb'],
153
m3 = Merge3(['aaa', 'bbb'],
154
['aaa', '111', 'bbb'],
159
157
self.assertEquals(m3.find_unconflicted(),
160
158
[(0, 1), (1, 2)])
170
168
('unchanged', 1, 2),])
172
170
def test_append_a(self):
173
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
174
['aaa\n', 'bbb\n', '222\n'],
171
m3 = Merge3(['aaa\n', 'bbb\n'],
172
['aaa\n', 'bbb\n', '222\n'],
177
175
self.assertEquals(''.join(m3.merge_lines()),
178
176
'aaa\nbbb\n222\n')
180
178
def test_append_b(self):
181
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
183
['aaa\n', 'bbb\n', '222\n'])
179
m3 = Merge3(['aaa\n', 'bbb\n'],
181
['aaa\n', 'bbb\n', '222\n'])
185
183
self.assertEquals(''.join(m3.merge_lines()),
186
184
'aaa\nbbb\n222\n')
188
186
def test_append_agreement(self):
189
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
190
['aaa\n', 'bbb\n', '222\n'],
191
['aaa\n', 'bbb\n', '222\n'])
187
m3 = Merge3(['aaa\n', 'bbb\n'],
188
['aaa\n', 'bbb\n', '222\n'],
189
['aaa\n', 'bbb\n', '222\n'])
193
191
self.assertEquals(''.join(m3.merge_lines()),
194
192
'aaa\nbbb\n222\n')
196
194
def test_append_clash(self):
197
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
198
['aaa\n', 'bbb\n', '222\n'],
199
['aaa\n', 'bbb\n', '333\n'])
195
m3 = Merge3(['aaa\n', 'bbb\n'],
196
['aaa\n', 'bbb\n', '222\n'],
197
['aaa\n', 'bbb\n', '333\n'])
201
199
ml = m3.merge_lines(name_a='a',
217
215
def test_insert_agreement(self):
218
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
219
['aaa\n', '222\n', 'bbb\n'],
220
['aaa\n', '222\n', 'bbb\n'])
216
m3 = Merge3(['aaa\n', 'bbb\n'],
217
['aaa\n', '222\n', 'bbb\n'],
218
['aaa\n', '222\n', 'bbb\n'])
222
220
ml = m3.merge_lines(name_a='a',
227
225
self.assertEquals(''.join(ml), 'aaa\n222\nbbb\n')
230
228
def test_insert_clash(self):
231
229
"""Both try to insert lines in the same place."""
232
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
233
['aaa\n', '111\n', 'bbb\n'],
234
['aaa\n', '222\n', 'bbb\n'])
230
m3 = Merge3(['aaa\n', 'bbb\n'],
231
['aaa\n', '111\n', 'bbb\n'],
232
['aaa\n', '222\n', 'bbb\n'])
236
234
self.assertEquals(m3.find_unconflicted(),
237
235
[(0, 1), (1, 2)])
270
268
def test_replace_clash(self):
271
269
"""Both try to insert lines in the same place."""
272
m3 = merge3.Merge3(['aaa', '000', 'bbb'],
273
['aaa', '111', 'bbb'],
274
['aaa', '222', 'bbb'])
270
m3 = Merge3(['aaa', '000', 'bbb'],
271
['aaa', '111', 'bbb'],
272
['aaa', '222', 'bbb'])
276
274
self.assertEquals(m3.find_unconflicted(),
277
275
[(0, 1), (2, 3)])
284
282
def test_replace_multi(self):
285
283
"""Replacement with regions of different size."""
286
m3 = merge3.Merge3(['aaa', '000', '000', 'bbb'],
287
['aaa', '111', '111', '111', 'bbb'],
288
['aaa', '222', '222', '222', '222', 'bbb'])
284
m3 = Merge3(['aaa', '000', '000', 'bbb'],
285
['aaa', '111', '111', '111', 'bbb'],
286
['aaa', '222', '222', '222', '222', 'bbb'])
290
288
self.assertEquals(m3.find_unconflicted(),
291
289
[(0, 1), (3, 4)])
299
297
def test_merge_poem(self):
300
298
"""Test case from diff3 manual"""
301
m3 = merge3.Merge3(TZU, LAO, TAO)
299
m3 = Merge3(TZU, LAO, TAO)
302
300
ml = list(m3.merge_lines('LAO', 'TAO'))
303
301
self.log('merge result:')
304
302
self.log(''.join(ml))
309
307
base_text = ("a\n" * 20).splitlines(True)
310
308
this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
311
309
other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True)
312
m3 = merge3.Merge3(base_text, other_text, this_text)
310
m3 = Merge3(base_text, other_text, this_text)
313
311
m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
314
312
merged_text = "".join(list(m_lines))
315
313
optimal_text = ("a\n" * 10 + "<<<<<<< OTHER\nc\n"
325
323
base_text = add_newline("abcdefghijklm")
326
324
this_text = add_newline("abcdefghijklmNOPQRSTUVWXYZ")
327
325
other_text = add_newline("abcdefghijklm1OPQRSTUVWXY2")
328
m3 = merge3.Merge3(base_text, other_text, this_text)
326
m3 = Merge3(base_text, other_text, this_text)
329
327
m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
330
328
merged_text = "".join(list(m_lines))
331
329
optimal_text = ''.join(add_newline("abcdefghijklm")
343
341
base_text = add_newline("abacddefgghij")
344
342
this_text = add_newline("abacddefgghijkalmontfprz")
345
343
other_text = add_newline("abacddefgghijknlmontfprd")
346
m3 = merge3.Merge3(base_text, other_text, this_text)
344
m3 = Merge3(base_text, other_text, this_text)
347
345
m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
348
346
merged_text = "".join(list(m_lines))
349
347
optimal_text = ''.join(add_newline("abacddefgghijk")
358
356
base_text = ("a\n" * 20).splitlines(True)
359
357
this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
360
358
other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True)
361
m3 = merge3.Merge3(base_text, other_text, this_text)
362
m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True,
359
m3 = Merge3(base_text, other_text, this_text)
360
m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True,
363
361
base_marker='|||||||')
364
362
self.assertRaises(CantReprocessAndShowBase, list, m_lines)
366
364
def test_binary(self):
367
self.assertRaises(BinaryFile, merge3.Merge3, ['\x00'], ['a'], ['b'])
365
self.assertRaises(BinaryFile, Merge3, ['\x00'], ['a'], ['b'])
369
367
def test_dos_text(self):
370
368
base_text = 'a\r\n'
371
369
this_text = 'b\r\n'
372
370
other_text = 'c\r\n'
373
m3 = merge3.Merge3(base_text.splitlines(True),
374
other_text.splitlines(True),
375
this_text.splitlines(True))
371
m3 = Merge3(base_text.splitlines(True), other_text.splitlines(True),
372
this_text.splitlines(True))
376
373
m_lines = m3.merge_lines('OTHER', 'THIS')
377
374
self.assertEqual('<<<<<<< OTHER\r\nc\r\n=======\r\nb\r\n'
378
375
'>>>>>>> THIS\r\n'.splitlines(True), list(m_lines))
381
378
base_text = 'a\r'
382
379
this_text = 'b\r'
383
380
other_text = 'c\r'
384
m3 = merge3.Merge3(base_text.splitlines(True),
385
other_text.splitlines(True),
386
this_text.splitlines(True))
381
m3 = Merge3(base_text.splitlines(True), other_text.splitlines(True),
382
this_text.splitlines(True))
387
383
m_lines = m3.merge_lines('OTHER', 'THIS')
388
384
self.assertEqual('<<<<<<< OTHER\rc\r=======\rb\r'
389
385
'>>>>>>> THIS\r'.splitlines(True), list(m_lines))
393
389
this_text = "a\n"
394
390
other_text = "a\nb\nc\n"
395
391
# When cherrypicking, lines in base are not part of the conflict
396
m3 = merge3.Merge3(base_text.splitlines(True),
397
this_text.splitlines(True),
398
other_text.splitlines(True), is_cherrypick=True)
392
m3 = Merge3(base_text.splitlines(True), this_text.splitlines(True),
393
other_text.splitlines(True), is_cherrypick=True)
399
394
m_lines = m3.merge_lines()
400
395
self.assertEqualDiff('a\n<<<<<<<\n=======\nc\n>>>>>>>\n',
401
396
''.join(m_lines))
403
398
# This is not symmetric
404
m3 = merge3.Merge3(base_text.splitlines(True),
405
other_text.splitlines(True),
406
this_text.splitlines(True), is_cherrypick=True)
399
m3 = Merge3(base_text.splitlines(True), other_text.splitlines(True),
400
this_text.splitlines(True), is_cherrypick=True)
407
401
m_lines = m3.merge_lines()
408
402
self.assertEqualDiff('a\n<<<<<<<\nb\nc\n=======\n>>>>>>>\n',
409
403
''.join(m_lines))
413
407
this_text = 'a\nb\nq\n'
414
408
other_text = 'a\nb\nc\nd\nf\ne\ng\n'
415
409
# When cherrypicking, lines in base are not part of the conflict
416
m3 = merge3.Merge3(base_text.splitlines(True),
417
this_text.splitlines(True),
418
other_text.splitlines(True), is_cherrypick=True)
410
m3 = Merge3(base_text.splitlines(True), this_text.splitlines(True),
411
other_text.splitlines(True), is_cherrypick=True)
419
412
m_lines = m3.merge_lines()
420
413
self.assertEqualDiff('a\n'
431
424
''.join(m_lines))
433
def test_allow_objects(self):
434
"""Objects other than strs may be used with Merge3 when
437
merge_groups and merge_regions work with non-str input. Methods that
438
return lines like merge_lines fail.
440
base = [(x,x) for x in 'abcde']
441
a = [(x,x) for x in 'abcdef']
442
b = [(x,x) for x in 'Zabcde']
443
m3 = merge3.Merge3(base, a, b, allow_objects=True)
448
list(m3.merge_regions()))
450
[('b', [('Z', 'Z')]),
451
('unchanged', [(x,x) for x in 'abcde']),
452
('a', [('f', 'f')])],
453
list(m3.merge_groups()))