~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testmerge3.py

  • Committer: Martin Pool
  • Date: 2005-09-13 00:47:09 UTC
  • mto: (1185.8.2) (974.1.91)
  • mto: This revision was merged to the branch mainline in revision 1390.
  • Revision ID: mbp@sourcefrog.net-20050913004709-ec9e0610b4239d5d
- name test tmpdirs sequentially, not randomly

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2004, 2005 by 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
 
18
 
from bzrlib import (
19
 
    errors,
20
 
    merge3,
21
 
    tests,
22
 
    )
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
 
 
18
from bzrlib.selftest import TestCaseInTempDir, TestCase
23
19
from bzrlib.merge3 import Merge3
24
 
from bzrlib.errors import CantReprocessAndShowBase, BinaryFile
25
20
 
26
21
def split_lines(t):
27
22
    from cStringIO import StringIO
32
27
# common base
33
28
TZU = split_lines("""     The Nameless is the origin of Heaven and Earth;
34
29
     The named is the mother of all things.
35
 
 
 
30
     
36
31
     Therefore let there always be non-being,
37
32
       so we may see their subtlety,
38
33
     And let there always be being,
63
58
     The name that can be named is not the eternal name.
64
59
     The Nameless is the origin of Heaven and Earth;
65
60
     The named is the mother of all things.
66
 
 
 
61
     
67
62
     Therefore let there always be non-being,
68
63
       so we may see their subtlety,
69
64
     And let there always be being,
71
66
     The two are the same,
72
67
     But after they are produced,
73
68
       they have different names.
74
 
 
 
69
     
75
70
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
76
71
 
77
72
""")
89
84
       they have different names.
90
85
<<<<<<< LAO
91
86
=======
92
 
 
 
87
     
93
88
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
94
89
 
95
90
>>>>>>> TAO
96
91
""")
97
92
 
98
 
class TestMerge3(tests.TestCase):
 
93
class TestMerge3(TestCase):
99
94
 
100
95
    def test_no_changes(self):
101
96
        """No conflicts because nothing changed"""
102
 
        m3 = merge3.Merge3(['aaa', 'bbb'],
103
 
                           ['aaa', 'bbb'],
104
 
                           ['aaa', 'bbb'])
 
97
        m3 = Merge3(['aaa', 'bbb'],
 
98
                    ['aaa', 'bbb'],
 
99
                    ['aaa', 'bbb'])
105
100
 
106
101
        self.assertEquals(m3.find_unconflicted(),
107
102
                          [(0, 2)])
119
114
                          [('unchanged', ['aaa', 'bbb'])])
120
115
 
121
116
    def test_front_insert(self):
122
 
        m3 = merge3.Merge3(['zz'],
123
 
                           ['aaa', 'bbb', 'zz'],
124
 
                           ['zz'])
 
117
        m3 = Merge3(['zz'],
 
118
                    ['aaa', 'bbb', 'zz'],
 
119
                    ['zz'])
125
120
 
126
121
        # todo: should use a sentinal at end as from get_matching_blocks
127
122
        # to match without zz
136
131
        self.assertEquals(list(m3.merge_groups()),
137
132
                          [('a', ['aaa', 'bbb']),
138
133
                           ('unchanged', ['zz'])])
139
 
 
 
134
        
140
135
    def test_null_insert(self):
141
 
        m3 = merge3.Merge3([],
142
 
                           ['aaa', 'bbb'],
143
 
                           [])
 
136
        m3 = Merge3([],
 
137
                    ['aaa', 'bbb'],
 
138
                    [])
144
139
        # todo: should use a sentinal at end as from get_matching_blocks
145
140
        # to match without zz
146
141
        self.assertEquals(list(m3.find_sync_regions()),
154
149
 
155
150
    def test_no_conflicts(self):
156
151
        """No conflicts because only one side changed"""
157
 
        m3 = merge3.Merge3(['aaa', 'bbb'],
158
 
                           ['aaa', '111', 'bbb'],
159
 
                           ['aaa', 'bbb'])
 
152
        m3 = Merge3(['aaa', 'bbb'],
 
153
                    ['aaa', '111', 'bbb'],
 
154
                    ['aaa', 'bbb'])
160
155
 
161
156
        self.assertEquals(m3.find_unconflicted(),
162
157
                          [(0, 1), (1, 2)])
172
167
                           ('unchanged', 1, 2),])
173
168
 
174
169
    def test_append_a(self):
175
 
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
176
 
                           ['aaa\n', 'bbb\n', '222\n'],
177
 
                           ['aaa\n', 'bbb\n'])
 
170
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
171
                    ['aaa\n', 'bbb\n', '222\n'],
 
172
                    ['aaa\n', 'bbb\n'])
178
173
 
179
174
        self.assertEquals(''.join(m3.merge_lines()),
180
175
                          'aaa\nbbb\n222\n')
181
176
 
182
177
    def test_append_b(self):
183
 
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
184
 
                           ['aaa\n', 'bbb\n'],
185
 
                           ['aaa\n', 'bbb\n', '222\n'])
 
178
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
179
                    ['aaa\n', 'bbb\n'],
 
180
                    ['aaa\n', 'bbb\n', '222\n'])
186
181
 
187
182
        self.assertEquals(''.join(m3.merge_lines()),
188
183
                          'aaa\nbbb\n222\n')
189
184
 
190
185
    def test_append_agreement(self):
191
 
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
192
 
                           ['aaa\n', 'bbb\n', '222\n'],
193
 
                           ['aaa\n', 'bbb\n', '222\n'])
 
186
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
187
                    ['aaa\n', 'bbb\n', '222\n'],
 
188
                    ['aaa\n', 'bbb\n', '222\n'])
194
189
 
195
190
        self.assertEquals(''.join(m3.merge_lines()),
196
191
                          'aaa\nbbb\n222\n')
197
192
 
198
193
    def test_append_clash(self):
199
 
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
200
 
                           ['aaa\n', 'bbb\n', '222\n'],
201
 
                           ['aaa\n', 'bbb\n', '333\n'])
 
194
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
195
                    ['aaa\n', 'bbb\n', '222\n'],
 
196
                    ['aaa\n', 'bbb\n', '333\n'])
202
197
 
203
198
        ml = m3.merge_lines(name_a='a',
204
199
                            name_b='b',
217
212
''')
218
213
 
219
214
    def test_insert_agreement(self):
220
 
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
221
 
                           ['aaa\n', '222\n', 'bbb\n'],
222
 
                           ['aaa\n', '222\n', 'bbb\n'])
 
215
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
216
                    ['aaa\n', '222\n', 'bbb\n'],
 
217
                    ['aaa\n', '222\n', 'bbb\n'])
223
218
 
224
219
        ml = m3.merge_lines(name_a='a',
225
220
                            name_b='b',
227
222
                            mid_marker='--',
228
223
                            end_marker='>>')
229
224
        self.assertEquals(''.join(ml), 'aaa\n222\nbbb\n')
230
 
 
 
225
        
231
226
 
232
227
    def test_insert_clash(self):
233
228
        """Both try to insert lines in the same place."""
234
 
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
235
 
                           ['aaa\n', '111\n', 'bbb\n'],
236
 
                           ['aaa\n', '222\n', 'bbb\n'])
 
229
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
230
                    ['aaa\n', '111\n', 'bbb\n'],
 
231
                    ['aaa\n', '222\n', 'bbb\n'])
237
232
 
238
233
        self.assertEquals(m3.find_unconflicted(),
239
234
                          [(0, 1), (1, 2)])
271
266
 
272
267
    def test_replace_clash(self):
273
268
        """Both try to insert lines in the same place."""
274
 
        m3 = merge3.Merge3(['aaa', '000', 'bbb'],
275
 
                           ['aaa', '111', 'bbb'],
276
 
                           ['aaa', '222', 'bbb'])
 
269
        m3 = Merge3(['aaa', '000', 'bbb'],
 
270
                    ['aaa', '111', 'bbb'],
 
271
                    ['aaa', '222', 'bbb'])
277
272
 
278
273
        self.assertEquals(m3.find_unconflicted(),
279
274
                          [(0, 1), (2, 3)])
285
280
 
286
281
    def test_replace_multi(self):
287
282
        """Replacement with regions of different size."""
288
 
        m3 = merge3.Merge3(['aaa', '000', '000', 'bbb'],
289
 
                           ['aaa', '111', '111', '111', 'bbb'],
290
 
                           ['aaa', '222', '222', '222', '222', 'bbb'])
 
283
        m3 = Merge3(['aaa', '000', '000', 'bbb'],
 
284
                    ['aaa', '111', '111', '111', 'bbb'],
 
285
                    ['aaa', '222', '222', '222', '222', 'bbb'])
291
286
 
292
287
        self.assertEquals(m3.find_unconflicted(),
293
288
                          [(0, 1), (3, 4)])
300
295
 
301
296
    def test_merge_poem(self):
302
297
        """Test case from diff3 manual"""
303
 
        m3 = merge3.Merge3(TZU, LAO, TAO)
 
298
        m3 = Merge3(TZU, LAO, TAO)
304
299
        ml = list(m3.merge_lines('LAO', 'TAO'))
305
300
        self.log('merge result:')
306
301
        self.log(''.join(ml))
307
302
        self.assertEquals(ml, MERGED_RESULT)
308
 
 
309
 
    def test_minimal_conflicts_common(self):
310
 
        """Reprocessing"""
311
 
        base_text = ("a\n" * 20).splitlines(True)
312
 
        this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
313
 
        other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True)
314
 
        m3 = merge3.Merge3(base_text, other_text, this_text)
315
 
        m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
316
 
        merged_text = "".join(list(m_lines))
317
 
        optimal_text = ("a\n" * 10 + "<<<<<<< OTHER\nc\n"
318
 
            + 8* "b\n" + "c\n=======\n"
319
 
            + 10*"b\n" + ">>>>>>> THIS\n")
320
 
        self.assertEqualDiff(optimal_text, merged_text)
321
 
 
322
 
    def test_minimal_conflicts_unique(self):
323
 
        def add_newline(s):
324
 
            """Add a newline to each entry in the string"""
325
 
            return [(x+'\n') for x in s]
326
 
 
327
 
        base_text = add_newline("abcdefghijklm")
328
 
        this_text = add_newline("abcdefghijklmNOPQRSTUVWXYZ")
329
 
        other_text = add_newline("abcdefghijklm1OPQRSTUVWXY2")
330
 
        m3 = merge3.Merge3(base_text, other_text, this_text)
331
 
        m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
332
 
        merged_text = "".join(list(m_lines))
333
 
        optimal_text = ''.join(add_newline("abcdefghijklm")
334
 
            + ["<<<<<<< OTHER\n1\n=======\nN\n>>>>>>> THIS\n"]
335
 
            + add_newline('OPQRSTUVWXY')
336
 
            + ["<<<<<<< OTHER\n2\n=======\nZ\n>>>>>>> THIS\n"]
337
 
            )
338
 
        self.assertEqualDiff(optimal_text, merged_text)
339
 
 
340
 
    def test_minimal_conflicts_nonunique(self):
341
 
        def add_newline(s):
342
 
            """Add a newline to each entry in the string"""
343
 
            return [(x+'\n') for x in s]
344
 
 
345
 
        base_text = add_newline("abacddefgghij")
346
 
        this_text = add_newline("abacddefgghijkalmontfprz")
347
 
        other_text = add_newline("abacddefgghijknlmontfprd")
348
 
        m3 = merge3.Merge3(base_text, other_text, this_text)
349
 
        m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
350
 
        merged_text = "".join(list(m_lines))
351
 
        optimal_text = ''.join(add_newline("abacddefgghijk")
352
 
            + ["<<<<<<< OTHER\nn\n=======\na\n>>>>>>> THIS\n"]
353
 
            + add_newline('lmontfpr')
354
 
            + ["<<<<<<< OTHER\nd\n=======\nz\n>>>>>>> THIS\n"]
355
 
            )
356
 
        self.assertEqualDiff(optimal_text, merged_text)
357
 
 
358
 
    def test_reprocess_and_base(self):
359
 
        """Reprocessing and showing base breaks correctly"""
360
 
        base_text = ("a\n" * 20).splitlines(True)
361
 
        this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
362
 
        other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True)
363
 
        m3 = merge3.Merge3(base_text, other_text, this_text)
364
 
        m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True,
365
 
                                 base_marker='|||||||')
366
 
        self.assertRaises(CantReprocessAndShowBase, list, m_lines)
367
 
 
368
 
    def test_binary(self):
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