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
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
23
from bzrlib.merge3 import Merge3
20
24
from bzrlib.errors import CantReprocessAndShowBase, BinaryFile
29
33
TZU = split_lines(""" The Nameless is the origin of Heaven and Earth;
30
34
The named is the mother of all things.
32
36
Therefore let there always be non-being,
33
37
so we may see their subtlety,
34
38
And let there always be being,
59
63
The name that can be named is not the eternal name.
60
64
The Nameless is the origin of Heaven and Earth;
61
65
The named is the mother of all things.
63
67
Therefore let there always be non-being,
64
68
so we may see their subtlety,
65
69
And let there always be being,
85
89
they have different names.
89
93
-- The Way of Lao-Tzu, tr. Wing-tsit Chan
94
class TestMerge3(TestCase):
98
class TestMerge3(tests.TestCase):
96
100
def test_no_changes(self):
97
101
"""No conflicts because nothing changed"""
98
m3 = Merge3(['aaa', 'bbb'],
102
m3 = merge3.Merge3(['aaa', 'bbb'],
102
106
self.assertEquals(m3.find_unconflicted(),
151
155
def test_no_conflicts(self):
152
156
"""No conflicts because only one side changed"""
153
m3 = Merge3(['aaa', 'bbb'],
154
['aaa', '111', 'bbb'],
157
m3 = merge3.Merge3(['aaa', 'bbb'],
158
['aaa', '111', 'bbb'],
157
161
self.assertEquals(m3.find_unconflicted(),
158
162
[(0, 1), (1, 2)])
168
172
('unchanged', 1, 2),])
170
174
def test_append_a(self):
171
m3 = Merge3(['aaa\n', 'bbb\n'],
172
['aaa\n', 'bbb\n', '222\n'],
175
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
176
['aaa\n', 'bbb\n', '222\n'],
175
179
self.assertEquals(''.join(m3.merge_lines()),
176
180
'aaa\nbbb\n222\n')
178
182
def test_append_b(self):
179
m3 = Merge3(['aaa\n', 'bbb\n'],
181
['aaa\n', 'bbb\n', '222\n'])
183
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
185
['aaa\n', 'bbb\n', '222\n'])
183
187
self.assertEquals(''.join(m3.merge_lines()),
184
188
'aaa\nbbb\n222\n')
186
190
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'])
191
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
192
['aaa\n', 'bbb\n', '222\n'],
193
['aaa\n', 'bbb\n', '222\n'])
191
195
self.assertEquals(''.join(m3.merge_lines()),
192
196
'aaa\nbbb\n222\n')
194
198
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'])
199
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
200
['aaa\n', 'bbb\n', '222\n'],
201
['aaa\n', 'bbb\n', '333\n'])
199
203
ml = m3.merge_lines(name_a='a',
215
219
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'])
220
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
221
['aaa\n', '222\n', 'bbb\n'],
222
['aaa\n', '222\n', 'bbb\n'])
220
224
ml = m3.merge_lines(name_a='a',
225
229
self.assertEquals(''.join(ml), 'aaa\n222\nbbb\n')
228
232
def test_insert_clash(self):
229
233
"""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'])
234
m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
235
['aaa\n', '111\n', 'bbb\n'],
236
['aaa\n', '222\n', 'bbb\n'])
234
238
self.assertEquals(m3.find_unconflicted(),
235
239
[(0, 1), (1, 2)])
268
272
def test_replace_clash(self):
269
273
"""Both try to insert lines in the same place."""
270
m3 = Merge3(['aaa', '000', 'bbb'],
271
['aaa', '111', 'bbb'],
272
['aaa', '222', 'bbb'])
274
m3 = merge3.Merge3(['aaa', '000', 'bbb'],
275
['aaa', '111', 'bbb'],
276
['aaa', '222', 'bbb'])
274
278
self.assertEquals(m3.find_unconflicted(),
275
279
[(0, 1), (2, 3)])
282
286
def test_replace_multi(self):
283
287
"""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'])
288
m3 = merge3.Merge3(['aaa', '000', '000', 'bbb'],
289
['aaa', '111', '111', '111', 'bbb'],
290
['aaa', '222', '222', '222', '222', 'bbb'])
288
292
self.assertEquals(m3.find_unconflicted(),
289
293
[(0, 1), (3, 4)])
297
301
def test_merge_poem(self):
298
302
"""Test case from diff3 manual"""
299
m3 = Merge3(TZU, LAO, TAO)
303
m3 = merge3.Merge3(TZU, LAO, TAO)
300
304
ml = list(m3.merge_lines('LAO', 'TAO'))
301
305
self.log('merge result:')
302
306
self.log(''.join(ml))
307
311
base_text = ("a\n" * 20).splitlines(True)
308
312
this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
309
313
other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True)
310
m3 = Merge3(base_text, other_text, this_text)
314
m3 = merge3.Merge3(base_text, other_text, this_text)
311
315
m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
312
316
merged_text = "".join(list(m_lines))
313
317
optimal_text = ("a\n" * 10 + "<<<<<<< OTHER\nc\n"
323
327
base_text = add_newline("abcdefghijklm")
324
328
this_text = add_newline("abcdefghijklmNOPQRSTUVWXYZ")
325
329
other_text = add_newline("abcdefghijklm1OPQRSTUVWXY2")
326
m3 = Merge3(base_text, other_text, this_text)
330
m3 = merge3.Merge3(base_text, other_text, this_text)
327
331
m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
328
332
merged_text = "".join(list(m_lines))
329
333
optimal_text = ''.join(add_newline("abcdefghijklm")
341
345
base_text = add_newline("abacddefgghij")
342
346
this_text = add_newline("abacddefgghijkalmontfprz")
343
347
other_text = add_newline("abacddefgghijknlmontfprd")
344
m3 = Merge3(base_text, other_text, this_text)
348
m3 = merge3.Merge3(base_text, other_text, this_text)
345
349
m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
346
350
merged_text = "".join(list(m_lines))
347
351
optimal_text = ''.join(add_newline("abacddefgghijk")
356
360
base_text = ("a\n" * 20).splitlines(True)
357
361
this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
358
362
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,
363
m3 = merge3.Merge3(base_text, other_text, this_text)
364
m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True,
361
365
base_marker='|||||||')
362
366
self.assertRaises(CantReprocessAndShowBase, list, m_lines)
364
368
def test_binary(self):
365
self.assertRaises(BinaryFile, Merge3, ['\x00'], ['a'], ['b'])
369
self.assertRaises(BinaryFile, merge3.Merge3, ['\x00'], ['a'], ['b'])
367
371
def test_dos_text(self):
368
372
base_text = 'a\r\n'
369
373
this_text = 'b\r\n'
370
374
other_text = 'c\r\n'
371
m3 = Merge3(base_text.splitlines(True), other_text.splitlines(True),
372
this_text.splitlines(True))
375
m3 = merge3.Merge3(base_text.splitlines(True),
376
other_text.splitlines(True),
377
this_text.splitlines(True))
373
378
m_lines = m3.merge_lines('OTHER', 'THIS')
374
379
self.assertEqual('<<<<<<< OTHER\r\nc\r\n=======\r\nb\r\n'
375
380
'>>>>>>> THIS\r\n'.splitlines(True), list(m_lines))
378
383
base_text = 'a\r'
379
384
this_text = 'b\r'
380
385
other_text = 'c\r'
381
m3 = Merge3(base_text.splitlines(True), other_text.splitlines(True),
382
this_text.splitlines(True))
386
m3 = merge3.Merge3(base_text.splitlines(True),
387
other_text.splitlines(True),
388
this_text.splitlines(True))
383
389
m_lines = m3.merge_lines('OTHER', 'THIS')
384
390
self.assertEqual('<<<<<<< OTHER\rc\r=======\rb\r'
385
391
'>>>>>>> THIS\r'.splitlines(True), list(m_lines))
389
395
this_text = "a\n"
390
396
other_text = "a\nb\nc\n"
391
397
# 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)
398
m3 = merge3.Merge3(base_text.splitlines(True),
399
this_text.splitlines(True),
400
other_text.splitlines(True), is_cherrypick=True)
394
401
m_lines = m3.merge_lines()
395
402
self.assertEqualDiff('a\n<<<<<<<\n=======\nc\n>>>>>>>\n',
396
403
''.join(m_lines))
398
405
# This is not symmetric
399
m3 = Merge3(base_text.splitlines(True), other_text.splitlines(True),
400
this_text.splitlines(True), is_cherrypick=True)
406
m3 = merge3.Merge3(base_text.splitlines(True),
407
other_text.splitlines(True),
408
this_text.splitlines(True), is_cherrypick=True)
401
409
m_lines = m3.merge_lines()
402
410
self.assertEqualDiff('a\n<<<<<<<\nb\nc\n=======\n>>>>>>>\n',
403
411
''.join(m_lines))
407
415
this_text = 'a\nb\nq\n'
408
416
other_text = 'a\nb\nc\nd\nf\ne\ng\n'
409
417
# 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)
418
m3 = merge3.Merge3(base_text.splitlines(True),
419
this_text.splitlines(True),
420
other_text.splitlines(True), is_cherrypick=True)
412
421
m_lines = m3.merge_lines()
413
422
self.assertEqualDiff('a\n'
424
433
''.join(m_lines))
435
def test_allow_objects(self):
436
"""Objects other than strs may be used with Merge3 when
439
merge_groups and merge_regions work with non-str input. Methods that
440
return lines like merge_lines fail.
442
base = [(x,x) for x in 'abcde']
443
a = [(x,x) for x in 'abcdef']
444
b = [(x,x) for x in 'Zabcde']
445
m3 = merge3.Merge3(base, a, b, allow_objects=True)
450
list(m3.merge_regions()))
452
[('b', [('Z', 'Z')]),
453
('unchanged', [(x,x) for x in 'abcde']),
454
('a', [('f', 'f')])],
455
list(m3.merge_groups()))