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