~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_merge3.py

(gz) Backslash escape selftest output when printing to non-unicode consoles
 (Martin [gz])

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
 
18
 
from bzrlib.tests import TestCaseInTempDir, TestCase
 
18
from bzrlib import (
 
19
    errors,
 
20
    merge3,
 
21
    tests,
 
22
    )
19
23
from bzrlib.merge3 import Merge3
20
24
from bzrlib.errors import CantReprocessAndShowBase, BinaryFile
21
25
 
91
95
>>>>>>> TAO
92
96
""")
93
97
 
94
 
class TestMerge3(TestCase):
 
98
class TestMerge3(tests.TestCase):
95
99
 
96
100
    def test_no_changes(self):
97
101
        """No conflicts because nothing changed"""
98
 
        m3 = Merge3(['aaa', 'bbb'],
99
 
                    ['aaa', 'bbb'],
100
 
                    ['aaa', 'bbb'])
 
102
        m3 = merge3.Merge3(['aaa', 'bbb'],
 
103
                           ['aaa', 'bbb'],
 
104
                           ['aaa', 'bbb'])
101
105
 
102
106
        self.assertEquals(m3.find_unconflicted(),
103
107
                          [(0, 2)])
115
119
                          [('unchanged', ['aaa', 'bbb'])])
116
120
 
117
121
    def test_front_insert(self):
118
 
        m3 = Merge3(['zz'],
119
 
                    ['aaa', 'bbb', 'zz'],
120
 
                    ['zz'])
 
122
        m3 = merge3.Merge3(['zz'],
 
123
                           ['aaa', 'bbb', 'zz'],
 
124
                           ['zz'])
121
125
 
122
126
        # todo: should use a sentinal at end as from get_matching_blocks
123
127
        # to match without zz
134
138
                           ('unchanged', ['zz'])])
135
139
 
136
140
    def test_null_insert(self):
137
 
        m3 = Merge3([],
138
 
                    ['aaa', 'bbb'],
139
 
                    [])
 
141
        m3 = merge3.Merge3([],
 
142
                           ['aaa', 'bbb'],
 
143
                           [])
140
144
        # todo: should use a sentinal at end as from get_matching_blocks
141
145
        # to match without zz
142
146
        self.assertEquals(list(m3.find_sync_regions()),
150
154
 
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'],
155
 
                    ['aaa', 'bbb'])
 
157
        m3 = merge3.Merge3(['aaa', 'bbb'],
 
158
                           ['aaa', '111', 'bbb'],
 
159
                           ['aaa', 'bbb'])
156
160
 
157
161
        self.assertEquals(m3.find_unconflicted(),
158
162
                          [(0, 1), (1, 2)])
168
172
                           ('unchanged', 1, 2),])
169
173
 
170
174
    def test_append_a(self):
171
 
        m3 = Merge3(['aaa\n', 'bbb\n'],
172
 
                    ['aaa\n', 'bbb\n', '222\n'],
173
 
                    ['aaa\n', 'bbb\n'])
 
175
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
 
176
                           ['aaa\n', 'bbb\n', '222\n'],
 
177
                           ['aaa\n', 'bbb\n'])
174
178
 
175
179
        self.assertEquals(''.join(m3.merge_lines()),
176
180
                          'aaa\nbbb\n222\n')
177
181
 
178
182
    def test_append_b(self):
179
 
        m3 = Merge3(['aaa\n', 'bbb\n'],
180
 
                    ['aaa\n', 'bbb\n'],
181
 
                    ['aaa\n', 'bbb\n', '222\n'])
 
183
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
 
184
                           ['aaa\n', 'bbb\n'],
 
185
                           ['aaa\n', 'bbb\n', '222\n'])
182
186
 
183
187
        self.assertEquals(''.join(m3.merge_lines()),
184
188
                          'aaa\nbbb\n222\n')
185
189
 
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'])
190
194
 
191
195
        self.assertEquals(''.join(m3.merge_lines()),
192
196
                          'aaa\nbbb\n222\n')
193
197
 
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'])
198
202
 
199
203
        ml = m3.merge_lines(name_a='a',
200
204
                            name_b='b',
213
217
''')
214
218
 
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'])
219
223
 
220
224
        ml = m3.merge_lines(name_a='a',
221
225
                            name_b='b',
227
231
 
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'])
233
237
 
234
238
        self.assertEquals(m3.find_unconflicted(),
235
239
                          [(0, 1), (1, 2)])
267
271
 
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'])
273
277
 
274
278
        self.assertEquals(m3.find_unconflicted(),
275
279
                          [(0, 1), (2, 3)])
281
285
 
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'])
287
291
 
288
292
        self.assertEquals(m3.find_unconflicted(),
289
293
                          [(0, 1), (3, 4)])
296
300
 
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)
 
363
        m3 = merge3.Merge3(base_text, other_text, this_text)
360
364
        m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True,
361
365
                                 base_marker='|||||||')
362
366
        self.assertRaises(CantReprocessAndShowBase, list, m_lines)
363
367
 
364
368
    def test_binary(self):
365
 
        self.assertRaises(BinaryFile, Merge3, ['\x00'], ['a'], ['b'])
 
369
        self.assertRaises(BinaryFile, merge3.Merge3, ['\x00'], ['a'], ['b'])
366
370
 
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))
397
404
 
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'
414
423
                             'b\n'
422
431
                             'g\n'
423
432
                             '>>>>>>>\n',
424
433
                             ''.join(m_lines))
 
434
 
 
435
    def test_allow_objects(self):
 
436
        """Objects other than strs may be used with Merge3 when
 
437
        allow_objects=True.
 
438
        
 
439
        merge_groups and merge_regions work with non-str input.  Methods that
 
440
        return lines like merge_lines fail.
 
441
        """
 
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)
 
446
        self.assertEqual(
 
447
            [('b', 0, 1),
 
448
             ('unchanged', 0, 5),
 
449
             ('a', 5, 6)],
 
450
            list(m3.merge_regions()))
 
451
        self.assertEqual(
 
452
            [('b', [('Z', 'Z')]),
 
453
             ('unchanged', [(x,x) for x in 'abcde']),
 
454
             ('a', [('f', 'f')])],
 
455
            list(m3.merge_groups()))
 
456