~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_merge3.py

  • Committer: Martin Pool
  • Date: 2010-06-02 05:03:31 UTC
  • mto: This revision was merged to the branch mainline in revision 5279.
  • Revision ID: mbp@canonical.com-20100602050331-n2p1qt8hfsahspnv
Correct more sloppy use of the term 'Linux'

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005-2010 Canonical Ltd
 
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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
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
16
 
 
17
 
 
18
 
from bzrlib.tests import TestCaseInTempDir, TestCase
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
 
 
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
 
28
32
# common base
29
33
TZU = split_lines("""     The Nameless is the origin of Heaven and Earth;
30
34
     The named is the mother of all things.
31
 
     
 
35
 
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.
62
 
     
 
66
 
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,
67
71
     The two are the same,
68
72
     But after they are produced,
69
73
       they have different names.
70
 
     
 
74
 
71
75
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
72
76
 
73
77
""")
85
89
       they have different names.
86
90
<<<<<<< LAO
87
91
=======
88
 
     
 
92
 
89
93
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
90
94
 
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
132
136
        self.assertEquals(list(m3.merge_groups()),
133
137
                          [('a', ['aaa', 'bbb']),
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',
223
227
                            mid_marker='--',
224
228
                            end_marker='>>')
225
229
        self.assertEquals(''.join(ml), 'aaa\n222\nbbb\n')
226
 
        
 
230
 
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)
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)
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'])
 
370
 
 
371
    def test_dos_text(self):
 
372
        base_text = 'a\r\n'
 
373
        this_text = 'b\r\n'
 
374
        other_text = 'c\r\n'
 
375
        m3 = merge3.Merge3(base_text.splitlines(True),
 
376
                           other_text.splitlines(True),
 
377
                           this_text.splitlines(True))
 
378
        m_lines = m3.merge_lines('OTHER', 'THIS')
 
379
        self.assertEqual('<<<<<<< OTHER\r\nc\r\n=======\r\nb\r\n'
 
380
            '>>>>>>> THIS\r\n'.splitlines(True), list(m_lines))
 
381
 
 
382
    def test_mac_text(self):
 
383
        base_text = 'a\r'
 
384
        this_text = 'b\r'
 
385
        other_text = 'c\r'
 
386
        m3 = merge3.Merge3(base_text.splitlines(True),
 
387
                           other_text.splitlines(True),
 
388
                           this_text.splitlines(True))
 
389
        m_lines = m3.merge_lines('OTHER', 'THIS')
 
390
        self.assertEqual('<<<<<<< OTHER\rc\r=======\rb\r'
 
391
            '>>>>>>> THIS\r'.splitlines(True), list(m_lines))
 
392
 
 
393
    def test_merge3_cherrypick(self):
 
394
        base_text = "a\nb\n"
 
395
        this_text = "a\n"
 
396
        other_text = "a\nb\nc\n"
 
397
        # When cherrypicking, lines in base are not part of the conflict
 
398
        m3 = merge3.Merge3(base_text.splitlines(True),
 
399
                           this_text.splitlines(True),
 
400
                           other_text.splitlines(True), is_cherrypick=True)
 
401
        m_lines = m3.merge_lines()
 
402
        self.assertEqualDiff('a\n<<<<<<<\n=======\nc\n>>>>>>>\n',
 
403
                             ''.join(m_lines))
 
404
 
 
405
        # This is not symmetric
 
406
        m3 = merge3.Merge3(base_text.splitlines(True),
 
407
                           other_text.splitlines(True),
 
408
                           this_text.splitlines(True), is_cherrypick=True)
 
409
        m_lines = m3.merge_lines()
 
410
        self.assertEqualDiff('a\n<<<<<<<\nb\nc\n=======\n>>>>>>>\n',
 
411
                             ''.join(m_lines))
 
412
 
 
413
    def test_merge3_cherrypick_w_mixed(self):
 
414
        base_text = 'a\nb\nc\nd\ne\n'
 
415
        this_text = 'a\nb\nq\n'
 
416
        other_text = 'a\nb\nc\nd\nf\ne\ng\n'
 
417
        # When cherrypicking, lines in base are not part of the conflict
 
418
        m3 = merge3.Merge3(base_text.splitlines(True),
 
419
                           this_text.splitlines(True),
 
420
                           other_text.splitlines(True), is_cherrypick=True)
 
421
        m_lines = m3.merge_lines()
 
422
        self.assertEqualDiff('a\n'
 
423
                             'b\n'
 
424
                             '<<<<<<<\n'
 
425
                             'q\n'
 
426
                             '=======\n'
 
427
                             'f\n'
 
428
                             '>>>>>>>\n'
 
429
                             '<<<<<<<\n'
 
430
                             '=======\n'
 
431
                             'g\n'
 
432
                             '>>>>>>>\n',
 
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