~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_merge3.py

  • Committer: Florent Gallaire
  • Date: 2017-03-17 10:39:02 UTC
  • mto: This revision was merged to the branch mainline in revision 6622.
  • Revision ID: fgallaire@gmail.com-20170317103902-xsmafws9vn8rczx9
Fix for Windows and 32-bit platforms buggy gmtime().

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005 Canonical Ltd
 
1
# Copyright (C) 2005-2011, 2016 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
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
19
 
from bzrlib.merge3 import Merge3
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
 
 
18
from bzrlib import (
 
19
    merge3,
 
20
    tests,
 
21
    )
20
22
from bzrlib.errors import CantReprocessAndShowBase, BinaryFile
21
23
 
22
24
def split_lines(t):
28
30
# common base
29
31
TZU = split_lines("""     The Nameless is the origin of Heaven and Earth;
30
32
     The named is the mother of all things.
31
 
     
 
33
 
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.
62
 
     
 
64
 
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,
67
69
     The two are the same,
68
70
     But after they are produced,
69
71
       they have different names.
70
 
     
 
72
 
71
73
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
72
74
 
73
75
""")
85
87
       they have different names.
86
88
<<<<<<< LAO
87
89
=======
88
 
     
 
90
 
89
91
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
90
92
 
91
93
>>>>>>> TAO
92
94
""")
93
95
 
94
 
class TestMerge3(TestCase):
 
96
class TestMerge3(tests.TestCase):
95
97
 
96
98
    def test_no_changes(self):
97
99
        """No conflicts because nothing changed"""
98
 
        m3 = Merge3(['aaa', 'bbb'],
99
 
                    ['aaa', 'bbb'],
100
 
                    ['aaa', 'bbb'])
 
100
        m3 = merge3.Merge3(['aaa', 'bbb'],
 
101
                           ['aaa', 'bbb'],
 
102
                           ['aaa', 'bbb'])
101
103
 
102
 
        self.assertEquals(m3.find_unconflicted(),
 
104
        self.assertEqual(m3.find_unconflicted(),
103
105
                          [(0, 2)])
104
106
 
105
 
        self.assertEquals(list(m3.find_sync_regions()),
 
107
        self.assertEqual(list(m3.find_sync_regions()),
106
108
                          [(0, 2,
107
109
                            0, 2,
108
110
                            0, 2),
109
111
                           (2,2, 2,2, 2,2)])
110
112
 
111
 
        self.assertEquals(list(m3.merge_regions()),
 
113
        self.assertEqual(list(m3.merge_regions()),
112
114
                          [('unchanged', 0, 2)])
113
115
 
114
 
        self.assertEquals(list(m3.merge_groups()),
 
116
        self.assertEqual(list(m3.merge_groups()),
115
117
                          [('unchanged', ['aaa', 'bbb'])])
116
118
 
117
119
    def test_front_insert(self):
118
 
        m3 = Merge3(['zz'],
119
 
                    ['aaa', 'bbb', 'zz'],
120
 
                    ['zz'])
 
120
        m3 = merge3.Merge3(['zz'],
 
121
                           ['aaa', 'bbb', 'zz'],
 
122
                           ['zz'])
121
123
 
122
124
        # todo: should use a sentinal at end as from get_matching_blocks
123
125
        # to match without zz
124
 
        self.assertEquals(list(m3.find_sync_regions()),
 
126
        self.assertEqual(list(m3.find_sync_regions()),
125
127
                          [(0,1, 2,3, 0,1),
126
128
                           (1,1, 3,3, 1,1),])
127
129
 
128
 
        self.assertEquals(list(m3.merge_regions()),
 
130
        self.assertEqual(list(m3.merge_regions()),
129
131
                          [('a', 0, 2),
130
132
                           ('unchanged', 0, 1)])
131
133
 
132
 
        self.assertEquals(list(m3.merge_groups()),
 
134
        self.assertEqual(list(m3.merge_groups()),
133
135
                          [('a', ['aaa', 'bbb']),
134
136
                           ('unchanged', ['zz'])])
135
 
        
 
137
 
136
138
    def test_null_insert(self):
137
 
        m3 = Merge3([],
138
 
                    ['aaa', 'bbb'],
139
 
                    [])
 
139
        m3 = merge3.Merge3([],
 
140
                           ['aaa', 'bbb'],
 
141
                           [])
140
142
        # todo: should use a sentinal at end as from get_matching_blocks
141
143
        # to match without zz
142
 
        self.assertEquals(list(m3.find_sync_regions()),
 
144
        self.assertEqual(list(m3.find_sync_regions()),
143
145
                          [(0,0, 2,2, 0,0)])
144
146
 
145
 
        self.assertEquals(list(m3.merge_regions()),
 
147
        self.assertEqual(list(m3.merge_regions()),
146
148
                          [('a', 0, 2)])
147
149
 
148
 
        self.assertEquals(list(m3.merge_lines()),
 
150
        self.assertEqual(list(m3.merge_lines()),
149
151
                          ['aaa', 'bbb'])
150
152
 
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
 
                    ['aaa', 'bbb'])
 
155
        m3 = merge3.Merge3(['aaa', 'bbb'],
 
156
                           ['aaa', '111', 'bbb'],
 
157
                           ['aaa', 'bbb'])
156
158
 
157
 
        self.assertEquals(m3.find_unconflicted(),
 
159
        self.assertEqual(m3.find_unconflicted(),
158
160
                          [(0, 1), (1, 2)])
159
161
 
160
 
        self.assertEquals(list(m3.find_sync_regions()),
 
162
        self.assertEqual(list(m3.find_sync_regions()),
161
163
                          [(0,1, 0,1, 0,1),
162
164
                           (1,2, 2,3, 1,2),
163
165
                           (2,2, 3,3, 2,2),])
164
166
 
165
 
        self.assertEquals(list(m3.merge_regions()),
 
167
        self.assertEqual(list(m3.merge_regions()),
166
168
                          [('unchanged', 0, 1),
167
169
                           ('a', 1, 2),
168
170
                           ('unchanged', 1, 2),])
169
171
 
170
172
    def test_append_a(self):
171
 
        m3 = Merge3(['aaa\n', 'bbb\n'],
172
 
                    ['aaa\n', 'bbb\n', '222\n'],
173
 
                    ['aaa\n', 'bbb\n'])
 
173
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
 
174
                           ['aaa\n', 'bbb\n', '222\n'],
 
175
                           ['aaa\n', 'bbb\n'])
174
176
 
175
 
        self.assertEquals(''.join(m3.merge_lines()),
 
177
        self.assertEqual(''.join(m3.merge_lines()),
176
178
                          'aaa\nbbb\n222\n')
177
179
 
178
180
    def test_append_b(self):
179
 
        m3 = Merge3(['aaa\n', 'bbb\n'],
180
 
                    ['aaa\n', 'bbb\n'],
181
 
                    ['aaa\n', 'bbb\n', '222\n'])
 
181
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
 
182
                           ['aaa\n', 'bbb\n'],
 
183
                           ['aaa\n', 'bbb\n', '222\n'])
182
184
 
183
 
        self.assertEquals(''.join(m3.merge_lines()),
 
185
        self.assertEqual(''.join(m3.merge_lines()),
184
186
                          'aaa\nbbb\n222\n')
185
187
 
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'])
190
192
 
191
 
        self.assertEquals(''.join(m3.merge_lines()),
 
193
        self.assertEqual(''.join(m3.merge_lines()),
192
194
                          'aaa\nbbb\n222\n')
193
195
 
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'])
198
200
 
199
201
        ml = m3.merge_lines(name_a='a',
200
202
                            name_b='b',
201
203
                            start_marker='<<',
202
204
                            mid_marker='--',
203
205
                            end_marker='>>')
204
 
        self.assertEquals(''.join(ml),
 
206
        self.assertEqual(''.join(ml),
205
207
'''\
206
208
aaa
207
209
bbb
213
215
''')
214
216
 
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'])
219
221
 
220
222
        ml = m3.merge_lines(name_a='a',
221
223
                            name_b='b',
222
224
                            start_marker='<<',
223
225
                            mid_marker='--',
224
226
                            end_marker='>>')
225
 
        self.assertEquals(''.join(ml), 'aaa\n222\nbbb\n')
226
 
        
 
227
        self.assertEqual(''.join(ml), 'aaa\n222\nbbb\n')
 
228
 
227
229
 
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'])
233
235
 
234
 
        self.assertEquals(m3.find_unconflicted(),
 
236
        self.assertEqual(m3.find_unconflicted(),
235
237
                          [(0, 1), (1, 2)])
236
238
 
237
 
        self.assertEquals(list(m3.find_sync_regions()),
 
239
        self.assertEqual(list(m3.find_sync_regions()),
238
240
                          [(0,1, 0,1, 0,1),
239
241
                           (1,2, 2,3, 2,3),
240
242
                           (2,2, 3,3, 3,3),])
241
243
 
242
 
        self.assertEquals(list(m3.merge_regions()),
 
244
        self.assertEqual(list(m3.merge_regions()),
243
245
                          [('unchanged', 0,1),
244
246
                           ('conflict', 1,1, 1,2, 1,2),
245
247
                           ('unchanged', 1,2)])
246
248
 
247
 
        self.assertEquals(list(m3.merge_groups()),
 
249
        self.assertEqual(list(m3.merge_groups()),
248
250
                          [('unchanged', ['aaa\n']),
249
251
                           ('conflict', [], ['111\n'], ['222\n']),
250
252
                           ('unchanged', ['bbb\n']),
255
257
                            start_marker='<<',
256
258
                            mid_marker='--',
257
259
                            end_marker='>>')
258
 
        self.assertEquals(''.join(ml),
 
260
        self.assertEqual(''.join(ml),
259
261
'''aaa
260
262
<< a
261
263
111
267
269
 
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'])
273
275
 
274
 
        self.assertEquals(m3.find_unconflicted(),
 
276
        self.assertEqual(m3.find_unconflicted(),
275
277
                          [(0, 1), (2, 3)])
276
278
 
277
 
        self.assertEquals(list(m3.find_sync_regions()),
 
279
        self.assertEqual(list(m3.find_sync_regions()),
278
280
                          [(0,1, 0,1, 0,1),
279
281
                           (2,3, 2,3, 2,3),
280
282
                           (3,3, 3,3, 3,3),])
281
283
 
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'])
287
289
 
288
 
        self.assertEquals(m3.find_unconflicted(),
 
290
        self.assertEqual(m3.find_unconflicted(),
289
291
                          [(0, 1), (3, 4)])
290
292
 
291
293
 
292
 
        self.assertEquals(list(m3.find_sync_regions()),
 
294
        self.assertEqual(list(m3.find_sync_regions()),
293
295
                          [(0,1, 0,1, 0,1),
294
296
                           (3,4, 4,5, 5,6),
295
297
                           (4,4, 5,5, 6,6),])
296
298
 
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))
303
 
        self.assertEquals(ml, MERGED_RESULT)
 
305
        self.assertEqual(ml, MERGED_RESULT)
304
306
 
305
307
    def test_minimal_conflicts_common(self):
306
308
        """Reprocessing"""
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)
363
365
 
364
366
    def test_binary(self):
365
 
        self.assertRaises(BinaryFile, Merge3, ['\x00'], ['a'], ['b'])
 
367
        self.assertRaises(BinaryFile, merge3.Merge3, ['\x00'], ['a'], ['b'])
366
368
 
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))
 
390
 
 
391
    def test_merge3_cherrypick(self):
 
392
        base_text = "a\nb\n"
 
393
        this_text = "a\n"
 
394
        other_text = "a\nb\nc\n"
 
395
        # When cherrypicking, lines in base are not part of the conflict
 
396
        m3 = merge3.Merge3(base_text.splitlines(True),
 
397
                           this_text.splitlines(True),
 
398
                           other_text.splitlines(True), is_cherrypick=True)
 
399
        m_lines = m3.merge_lines()
 
400
        self.assertEqualDiff('a\n<<<<<<<\n=======\nc\n>>>>>>>\n',
 
401
                             ''.join(m_lines))
 
402
 
 
403
        # This is not symmetric
 
404
        m3 = merge3.Merge3(base_text.splitlines(True),
 
405
                           other_text.splitlines(True),
 
406
                           this_text.splitlines(True), is_cherrypick=True)
 
407
        m_lines = m3.merge_lines()
 
408
        self.assertEqualDiff('a\n<<<<<<<\nb\nc\n=======\n>>>>>>>\n',
 
409
                             ''.join(m_lines))
 
410
 
 
411
    def test_merge3_cherrypick_w_mixed(self):
 
412
        base_text = 'a\nb\nc\nd\ne\n'
 
413
        this_text = 'a\nb\nq\n'
 
414
        other_text = 'a\nb\nc\nd\nf\ne\ng\n'
 
415
        # When cherrypicking, lines in base are not part of the conflict
 
416
        m3 = merge3.Merge3(base_text.splitlines(True),
 
417
                           this_text.splitlines(True),
 
418
                           other_text.splitlines(True), is_cherrypick=True)
 
419
        m_lines = m3.merge_lines()
 
420
        self.assertEqualDiff('a\n'
 
421
                             'b\n'
 
422
                             '<<<<<<<\n'
 
423
                             'q\n'
 
424
                             '=======\n'
 
425
                             'f\n'
 
426
                             '>>>>>>>\n'
 
427
                             '<<<<<<<\n'
 
428
                             '=======\n'
 
429
                             'g\n'
 
430
                             '>>>>>>>\n',
 
431
                             ''.join(m_lines))
 
432
 
 
433
    def test_allow_objects(self):
 
434
        """Objects other than strs may be used with Merge3 when
 
435
        allow_objects=True.
 
436
        
 
437
        merge_groups and merge_regions work with non-str input.  Methods that
 
438
        return lines like merge_lines fail.
 
439
        """
 
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)
 
444
        self.assertEqual(
 
445
            [('b', 0, 1),
 
446
             ('unchanged', 0, 5),
 
447
             ('a', 5, 6)],
 
448
            list(m3.merge_regions()))
 
449
        self.assertEqual(
 
450
            [('b', [('Z', 'Z')]),
 
451
             ('unchanged', [(x,x) for x in 'abcde']),
 
452
             ('a', [('f', 'f')])],
 
453
            list(m3.merge_groups()))
 
454