/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testmerge3.py

[merge] robertc's integration, updated tests to check for retcode=3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011, 2016 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 .. import (
19
 
    merge3,
20
 
    tests,
21
 
    )
22
 
from ..errors import BinaryFile
23
 
from ..sixish import (
24
 
    BytesIO,
25
 
    int2byte,
26
 
    )
27
 
 
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
 
 
18
from bzrlib.selftest import TestCaseInTempDir, TestCase
 
19
from bzrlib.merge3 import Merge3
 
20
from bzrlib.errors import CantReprocessAndShowBase
28
21
 
29
22
def split_lines(t):
30
 
    return BytesIO(t).readlines()
31
 
 
 
23
    from cStringIO import StringIO
 
24
    return StringIO(t).readlines()
32
25
 
33
26
############################################################
34
27
# test case data from the gnu diffutils manual
35
28
# common base
36
 
TZU = split_lines(b"""     The Nameless is the origin of Heaven and Earth;
 
29
TZU = split_lines("""     The Nameless is the origin of Heaven and Earth;
37
30
     The named is the mother of all things.
38
 
 
 
31
     
39
32
     Therefore let there always be non-being,
40
33
       so we may see their subtlety,
41
34
     And let there always be being,
48
41
     The door of all subtleties!
49
42
""")
50
43
 
51
 
LAO = split_lines(b"""     The Way that can be told of is not the eternal Way;
 
44
LAO = split_lines("""     The Way that can be told of is not the eternal Way;
52
45
     The name that can be named is not the eternal name.
53
46
     The Nameless is the origin of Heaven and Earth;
54
47
     The Named is the mother of all things.
62
55
""")
63
56
 
64
57
 
65
 
TAO = split_lines(b"""     The Way that can be told of is not the eternal Way;
 
58
TAO = split_lines("""     The Way that can be told of is not the eternal Way;
66
59
     The name that can be named is not the eternal name.
67
60
     The Nameless is the origin of Heaven and Earth;
68
61
     The named is the mother of all things.
69
 
 
 
62
     
70
63
     Therefore let there always be non-being,
71
64
       so we may see their subtlety,
72
65
     And let there always be being,
74
67
     The two are the same,
75
68
     But after they are produced,
76
69
       they have different names.
77
 
 
 
70
     
78
71
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
79
72
 
80
73
""")
81
74
 
82
 
MERGED_RESULT = split_lines(b"""     The Way that can be told of is not the eternal Way;
 
75
MERGED_RESULT = split_lines("""     The Way that can be told of is not the eternal Way;
83
76
     The name that can be named is not the eternal name.
84
77
     The Nameless is the origin of Heaven and Earth;
85
78
     The Named is the mother of all things.
92
85
       they have different names.
93
86
<<<<<<< LAO
94
87
=======
95
 
 
 
88
     
96
89
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
97
90
 
98
91
>>>>>>> TAO
99
92
""")
100
93
 
101
 
 
102
 
class TestMerge3(tests.TestCase):
 
94
class TestMerge3(TestCase):
103
95
 
104
96
    def test_no_changes(self):
105
97
        """No conflicts because nothing changed"""
106
 
        m3 = merge3.Merge3([b'aaa', b'bbb'],
107
 
                           [b'aaa', b'bbb'],
108
 
                           [b'aaa', b'bbb'])
109
 
 
110
 
        self.assertEqual(m3.find_unconflicted(),
111
 
                         [(0, 2)])
112
 
 
113
 
        self.assertEqual(list(m3.find_sync_regions()),
114
 
                         [(0, 2,
115
 
                           0, 2,
116
 
                           0, 2),
117
 
                          (2, 2, 2, 2, 2, 2)])
118
 
 
119
 
        self.assertEqual(list(m3.merge_regions()),
120
 
                         [('unchanged', 0, 2)])
121
 
 
122
 
        self.assertEqual(list(m3.merge_groups()),
123
 
                         [('unchanged', [b'aaa', b'bbb'])])
 
98
        m3 = Merge3(['aaa', 'bbb'],
 
99
                    ['aaa', 'bbb'],
 
100
                    ['aaa', 'bbb'])
 
101
 
 
102
        self.assertEquals(m3.find_unconflicted(),
 
103
                          [(0, 2)])
 
104
 
 
105
        self.assertEquals(list(m3.find_sync_regions()),
 
106
                          [(0, 2,
 
107
                            0, 2,
 
108
                            0, 2),
 
109
                           (2,2, 2,2, 2,2)])
 
110
 
 
111
        self.assertEquals(list(m3.merge_regions()),
 
112
                          [('unchanged', 0, 2)])
 
113
 
 
114
        self.assertEquals(list(m3.merge_groups()),
 
115
                          [('unchanged', ['aaa', 'bbb'])])
124
116
 
125
117
    def test_front_insert(self):
126
 
        m3 = merge3.Merge3([b'zz'],
127
 
                           [b'aaa', b'bbb', b'zz'],
128
 
                           [b'zz'])
 
118
        m3 = Merge3(['zz'],
 
119
                    ['aaa', 'bbb', 'zz'],
 
120
                    ['zz'])
129
121
 
130
122
        # todo: should use a sentinal at end as from get_matching_blocks
131
123
        # to match without zz
132
 
        self.assertEqual(list(m3.find_sync_regions()),
133
 
                         [(0, 1, 2, 3, 0, 1),
134
 
                          (1, 1, 3, 3, 1, 1), ])
135
 
 
136
 
        self.assertEqual(list(m3.merge_regions()),
137
 
                         [('a', 0, 2),
138
 
                          ('unchanged', 0, 1)])
139
 
 
140
 
        self.assertEqual(list(m3.merge_groups()),
141
 
                         [('a', [b'aaa', b'bbb']),
142
 
                          ('unchanged', [b'zz'])])
143
 
 
 
124
        self.assertEquals(list(m3.find_sync_regions()),
 
125
                          [(0,1, 2,3, 0,1),
 
126
                           (1,1, 3,3, 1,1),])
 
127
 
 
128
        self.assertEquals(list(m3.merge_regions()),
 
129
                          [('a', 0, 2),
 
130
                           ('unchanged', 0, 1)])
 
131
 
 
132
        self.assertEquals(list(m3.merge_groups()),
 
133
                          [('a', ['aaa', 'bbb']),
 
134
                           ('unchanged', ['zz'])])
 
135
        
144
136
    def test_null_insert(self):
145
 
        m3 = merge3.Merge3([],
146
 
                           [b'aaa', b'bbb'],
147
 
                           [])
 
137
        m3 = Merge3([],
 
138
                    ['aaa', 'bbb'],
 
139
                    [])
148
140
        # todo: should use a sentinal at end as from get_matching_blocks
149
141
        # to match without zz
150
 
        self.assertEqual(list(m3.find_sync_regions()),
151
 
                         [(0, 0, 2, 2, 0, 0)])
152
 
 
153
 
        self.assertEqual(list(m3.merge_regions()),
154
 
                         [('a', 0, 2)])
155
 
 
156
 
        self.assertEqual(list(m3.merge_lines()),
157
 
                         [b'aaa', b'bbb'])
 
142
        self.assertEquals(list(m3.find_sync_regions()),
 
143
                          [(0,0, 2,2, 0,0)])
 
144
 
 
145
        self.assertEquals(list(m3.merge_regions()),
 
146
                          [('a', 0, 2)])
 
147
 
 
148
        self.assertEquals(list(m3.merge_lines()),
 
149
                          ['aaa', 'bbb'])
158
150
 
159
151
    def test_no_conflicts(self):
160
152
        """No conflicts because only one side changed"""
161
 
        m3 = merge3.Merge3([b'aaa', b'bbb'],
162
 
                           [b'aaa', b'111', b'bbb'],
163
 
                           [b'aaa', b'bbb'])
164
 
 
165
 
        self.assertEqual(m3.find_unconflicted(),
166
 
                         [(0, 1), (1, 2)])
167
 
 
168
 
        self.assertEqual(list(m3.find_sync_regions()),
169
 
                         [(0, 1, 0, 1, 0, 1),
170
 
                          (1, 2, 2, 3, 1, 2),
171
 
                          (2, 2, 3, 3, 2, 2), ])
172
 
 
173
 
        self.assertEqual(list(m3.merge_regions()),
174
 
                         [('unchanged', 0, 1),
175
 
                          ('a', 1, 2),
176
 
                          ('unchanged', 1, 2), ])
 
153
        m3 = Merge3(['aaa', 'bbb'],
 
154
                    ['aaa', '111', 'bbb'],
 
155
                    ['aaa', 'bbb'])
 
156
 
 
157
        self.assertEquals(m3.find_unconflicted(),
 
158
                          [(0, 1), (1, 2)])
 
159
 
 
160
        self.assertEquals(list(m3.find_sync_regions()),
 
161
                          [(0,1, 0,1, 0,1),
 
162
                           (1,2, 2,3, 1,2),
 
163
                           (2,2, 3,3, 2,2),])
 
164
 
 
165
        self.assertEquals(list(m3.merge_regions()),
 
166
                          [('unchanged', 0, 1),
 
167
                           ('a', 1, 2),
 
168
                           ('unchanged', 1, 2),])
177
169
 
178
170
    def test_append_a(self):
179
 
        m3 = merge3.Merge3([b'aaa\n', b'bbb\n'],
180
 
                           [b'aaa\n', b'bbb\n', b'222\n'],
181
 
                           [b'aaa\n', b'bbb\n'])
 
171
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
172
                    ['aaa\n', 'bbb\n', '222\n'],
 
173
                    ['aaa\n', 'bbb\n'])
182
174
 
183
 
        self.assertEqual(b''.join(m3.merge_lines()),
184
 
                         b'aaa\nbbb\n222\n')
 
175
        self.assertEquals(''.join(m3.merge_lines()),
 
176
                          'aaa\nbbb\n222\n')
185
177
 
186
178
    def test_append_b(self):
187
 
        m3 = merge3.Merge3([b'aaa\n', b'bbb\n'],
188
 
                           [b'aaa\n', b'bbb\n'],
189
 
                           [b'aaa\n', b'bbb\n', b'222\n'])
 
179
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
180
                    ['aaa\n', 'bbb\n'],
 
181
                    ['aaa\n', 'bbb\n', '222\n'])
190
182
 
191
 
        self.assertEqual(b''.join(m3.merge_lines()),
192
 
                         b'aaa\nbbb\n222\n')
 
183
        self.assertEquals(''.join(m3.merge_lines()),
 
184
                          'aaa\nbbb\n222\n')
193
185
 
194
186
    def test_append_agreement(self):
195
 
        m3 = merge3.Merge3([b'aaa\n', b'bbb\n'],
196
 
                           [b'aaa\n', b'bbb\n', b'222\n'],
197
 
                           [b'aaa\n', b'bbb\n', b'222\n'])
 
187
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
188
                    ['aaa\n', 'bbb\n', '222\n'],
 
189
                    ['aaa\n', 'bbb\n', '222\n'])
198
190
 
199
 
        self.assertEqual(b''.join(m3.merge_lines()),
200
 
                         b'aaa\nbbb\n222\n')
 
191
        self.assertEquals(''.join(m3.merge_lines()),
 
192
                          'aaa\nbbb\n222\n')
201
193
 
202
194
    def test_append_clash(self):
203
 
        m3 = merge3.Merge3([b'aaa\n', b'bbb\n'],
204
 
                           [b'aaa\n', b'bbb\n', b'222\n'],
205
 
                           [b'aaa\n', b'bbb\n', b'333\n'])
 
195
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
196
                    ['aaa\n', 'bbb\n', '222\n'],
 
197
                    ['aaa\n', 'bbb\n', '333\n'])
206
198
 
207
 
        ml = m3.merge_lines(name_a=b'a',
208
 
                            name_b=b'b',
209
 
                            start_marker=b'<<',
210
 
                            mid_marker=b'--',
211
 
                            end_marker=b'>>')
212
 
        self.assertEqual(b''.join(ml),
213
 
                         b'''\
 
199
        ml = m3.merge_lines(name_a='a',
 
200
                            name_b='b',
 
201
                            start_marker='<<',
 
202
                            mid_marker='--',
 
203
                            end_marker='>>')
 
204
        self.assertEquals(''.join(ml),
 
205
'''\
214
206
aaa
215
207
bbb
216
208
<< a
221
213
''')
222
214
 
223
215
    def test_insert_agreement(self):
224
 
        m3 = merge3.Merge3([b'aaa\n', b'bbb\n'],
225
 
                           [b'aaa\n', b'222\n', b'bbb\n'],
226
 
                           [b'aaa\n', b'222\n', b'bbb\n'])
 
216
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
217
                    ['aaa\n', '222\n', 'bbb\n'],
 
218
                    ['aaa\n', '222\n', 'bbb\n'])
227
219
 
228
 
        ml = m3.merge_lines(name_a=b'a',
229
 
                            name_b=b'b',
230
 
                            start_marker=b'<<',
231
 
                            mid_marker=b'--',
232
 
                            end_marker=b'>>')
233
 
        self.assertEqual(b''.join(ml), b'aaa\n222\nbbb\n')
 
220
        ml = m3.merge_lines(name_a='a',
 
221
                            name_b='b',
 
222
                            start_marker='<<',
 
223
                            mid_marker='--',
 
224
                            end_marker='>>')
 
225
        self.assertEquals(''.join(ml), 'aaa\n222\nbbb\n')
 
226
        
234
227
 
235
228
    def test_insert_clash(self):
236
229
        """Both try to insert lines in the same place."""
237
 
        m3 = merge3.Merge3([b'aaa\n', b'bbb\n'],
238
 
                           [b'aaa\n', b'111\n', b'bbb\n'],
239
 
                           [b'aaa\n', b'222\n', b'bbb\n'])
240
 
 
241
 
        self.assertEqual(m3.find_unconflicted(),
242
 
                         [(0, 1), (1, 2)])
243
 
 
244
 
        self.assertEqual(list(m3.find_sync_regions()),
245
 
                         [(0, 1, 0, 1, 0, 1),
246
 
                          (1, 2, 2, 3, 2, 3),
247
 
                          (2, 2, 3, 3, 3, 3), ])
248
 
 
249
 
        self.assertEqual(list(m3.merge_regions()),
250
 
                         [('unchanged', 0, 1),
251
 
                          ('conflict', 1, 1, 1, 2, 1, 2),
252
 
                          ('unchanged', 1, 2)])
253
 
 
254
 
        self.assertEqual(list(m3.merge_groups()),
255
 
                         [('unchanged', [b'aaa\n']),
256
 
                          ('conflict', [], [b'111\n'], [b'222\n']),
257
 
                          ('unchanged', [b'bbb\n']),
258
 
                          ])
259
 
 
260
 
        ml = m3.merge_lines(name_a=b'a',
261
 
                            name_b=b'b',
262
 
                            start_marker=b'<<',
263
 
                            mid_marker=b'--',
264
 
                            end_marker=b'>>')
265
 
        self.assertEqual(b''.join(ml),
266
 
                         b'''aaa
 
230
        m3 = Merge3(['aaa\n', 'bbb\n'],
 
231
                    ['aaa\n', '111\n', 'bbb\n'],
 
232
                    ['aaa\n', '222\n', 'bbb\n'])
 
233
 
 
234
        self.assertEquals(m3.find_unconflicted(),
 
235
                          [(0, 1), (1, 2)])
 
236
 
 
237
        self.assertEquals(list(m3.find_sync_regions()),
 
238
                          [(0,1, 0,1, 0,1),
 
239
                           (1,2, 2,3, 2,3),
 
240
                           (2,2, 3,3, 3,3),])
 
241
 
 
242
        self.assertEquals(list(m3.merge_regions()),
 
243
                          [('unchanged', 0,1),
 
244
                           ('conflict', 1,1, 1,2, 1,2),
 
245
                           ('unchanged', 1,2)])
 
246
 
 
247
        self.assertEquals(list(m3.merge_groups()),
 
248
                          [('unchanged', ['aaa\n']),
 
249
                           ('conflict', [], ['111\n'], ['222\n']),
 
250
                           ('unchanged', ['bbb\n']),
 
251
                           ])
 
252
 
 
253
        ml = m3.merge_lines(name_a='a',
 
254
                            name_b='b',
 
255
                            start_marker='<<',
 
256
                            mid_marker='--',
 
257
                            end_marker='>>')
 
258
        self.assertEquals(''.join(ml),
 
259
'''aaa
267
260
<< a
268
261
111
269
262
--
274
267
 
275
268
    def test_replace_clash(self):
276
269
        """Both try to insert lines in the same place."""
277
 
        m3 = merge3.Merge3([b'aaa', b'000', b'bbb'],
278
 
                           [b'aaa', b'111', b'bbb'],
279
 
                           [b'aaa', b'222', b'bbb'])
280
 
 
281
 
        self.assertEqual(m3.find_unconflicted(),
282
 
                         [(0, 1), (2, 3)])
283
 
 
284
 
        self.assertEqual(list(m3.find_sync_regions()),
285
 
                         [(0, 1, 0, 1, 0, 1),
286
 
                          (2, 3, 2, 3, 2, 3),
287
 
                          (3, 3, 3, 3, 3, 3), ])
 
270
        m3 = Merge3(['aaa', '000', 'bbb'],
 
271
                    ['aaa', '111', 'bbb'],
 
272
                    ['aaa', '222', 'bbb'])
 
273
 
 
274
        self.assertEquals(m3.find_unconflicted(),
 
275
                          [(0, 1), (2, 3)])
 
276
 
 
277
        self.assertEquals(list(m3.find_sync_regions()),
 
278
                          [(0,1, 0,1, 0,1),
 
279
                           (2,3, 2,3, 2,3),
 
280
                           (3,3, 3,3, 3,3),])
288
281
 
289
282
    def test_replace_multi(self):
290
283
        """Replacement with regions of different size."""
291
 
        m3 = merge3.Merge3([b'aaa', b'000', b'000', b'bbb'],
292
 
                           [b'aaa', b'111', b'111', b'111', b'bbb'],
293
 
                           [b'aaa', b'222', b'222', b'222', b'222', b'bbb'])
294
 
 
295
 
        self.assertEqual(m3.find_unconflicted(),
296
 
                         [(0, 1), (3, 4)])
297
 
 
298
 
        self.assertEqual(list(m3.find_sync_regions()),
299
 
                         [(0, 1, 0, 1, 0, 1),
300
 
                          (3, 4, 4, 5, 5, 6),
301
 
                          (4, 4, 5, 5, 6, 6), ])
 
284
        m3 = Merge3(['aaa', '000', '000', 'bbb'],
 
285
                    ['aaa', '111', '111', '111', 'bbb'],
 
286
                    ['aaa', '222', '222', '222', '222', 'bbb'])
 
287
 
 
288
        self.assertEquals(m3.find_unconflicted(),
 
289
                          [(0, 1), (3, 4)])
 
290
 
 
291
 
 
292
        self.assertEquals(list(m3.find_sync_regions()),
 
293
                          [(0,1, 0,1, 0,1),
 
294
                           (3,4, 4,5, 5,6),
 
295
                           (4,4, 5,5, 6,6),])
302
296
 
303
297
    def test_merge_poem(self):
304
298
        """Test case from diff3 manual"""
305
 
        m3 = merge3.Merge3(TZU, LAO, TAO)
306
 
        ml = list(m3.merge_lines(b'LAO', b'TAO'))
 
299
        m3 = Merge3(TZU, LAO, TAO)
 
300
        ml = list(m3.merge_lines('LAO', 'TAO'))
307
301
        self.log('merge result:')
308
 
        self.log(b''.join(ml))
309
 
        self.assertEqual(ml, MERGED_RESULT)
 
302
        self.log(''.join(ml))
 
303
        self.assertEquals(ml, MERGED_RESULT)
310
304
 
311
 
    def test_minimal_conflicts_common(self):
 
305
    def test_minimal_conflicts(self):
312
306
        """Reprocessing"""
313
 
        base_text = (b"a\n" * 20).splitlines(True)
314
 
        this_text = (b"a\n" * 10 + b"b\n" * 10).splitlines(True)
315
 
        other_text = (b"a\n" * 10 + b"c\n" + b"b\n" *
316
 
                      8 + b"c\n").splitlines(True)
317
 
        m3 = merge3.Merge3(base_text, other_text, this_text)
318
 
        m_lines = m3.merge_lines(b'OTHER', b'THIS', reprocess=True)
319
 
        merged_text = b"".join(list(m_lines))
320
 
        optimal_text = (b"a\n" * 10 + b"<<<<<<< OTHER\nc\n"
321
 
                        + 8 * b"b\n" + b"c\n=======\n"
322
 
                        + 10 * b"b\n" + b">>>>>>> THIS\n")
323
 
        self.assertEqualDiff(optimal_text, merged_text)
324
 
 
325
 
    def test_minimal_conflicts_unique(self):
326
 
        def add_newline(s):
327
 
            """Add a newline to each entry in the string"""
328
 
            return [(int2byte(x) + b'\n') for x in bytearray(s)]
329
 
 
330
 
        base_text = add_newline(b"abcdefghijklm")
331
 
        this_text = add_newline(b"abcdefghijklmNOPQRSTUVWXYZ")
332
 
        other_text = add_newline(b"abcdefghijklm1OPQRSTUVWXY2")
333
 
        m3 = merge3.Merge3(base_text, other_text, this_text)
334
 
        m_lines = m3.merge_lines(b'OTHER', b'THIS', reprocess=True)
335
 
        merged_text = b"".join(list(m_lines))
336
 
        optimal_text = b''.join(add_newline(b"abcdefghijklm")
337
 
                                + [b"<<<<<<< OTHER\n1\n=======\nN\n>>>>>>> THIS\n"]
338
 
                                + add_newline(b'OPQRSTUVWXY')
339
 
                                + [b"<<<<<<< OTHER\n2\n=======\nZ\n>>>>>>> THIS\n"]
340
 
                                )
341
 
        self.assertEqualDiff(optimal_text, merged_text)
342
 
 
343
 
    def test_minimal_conflicts_nonunique(self):
344
 
        def add_newline(s):
345
 
            """Add a newline to each entry in the string"""
346
 
            return [(int2byte(x) + b'\n') for x in bytearray(s)]
347
 
 
348
 
        base_text = add_newline(b"abacddefgghij")
349
 
        this_text = add_newline(b"abacddefgghijkalmontfprz")
350
 
        other_text = add_newline(b"abacddefgghijknlmontfprd")
351
 
        m3 = merge3.Merge3(base_text, other_text, this_text)
352
 
        m_lines = m3.merge_lines(b'OTHER', b'THIS', reprocess=True)
353
 
        merged_text = b"".join(list(m_lines))
354
 
        optimal_text = b''.join(add_newline(b"abacddefgghijk")
355
 
                                + [b"<<<<<<< OTHER\nn\n=======\na\n>>>>>>> THIS\n"]
356
 
                                + add_newline(b'lmontfpr')
357
 
                                + [b"<<<<<<< OTHER\nd\n=======\nz\n>>>>>>> THIS\n"]
358
 
                                )
359
 
        self.assertEqualDiff(optimal_text, merged_text)
 
307
        base_text = ("a\n" * 20).splitlines(True)
 
308
        this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
 
309
        other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True)
 
310
        m3 = Merge3(base_text, other_text, this_text)
 
311
        m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
 
312
        merged_text = "".join(list(m_lines))
 
313
        optimal_text = "a\n" * 10 + "<<<<<<< OTHER\nc\n=======\n>>>>>>> THIS"\
 
314
            + "\n" + 8* "b\n" + "<<<<<<< OTHER\nc\n=======\nb\nb\n>>>>>>>"\
 
315
            + " THIS\n"
 
316
        self.assertEqualDiff(merged_text, optimal_text)
360
317
 
361
318
    def test_reprocess_and_base(self):
362
319
        """Reprocessing and showing base breaks correctly"""
363
 
        base_text = (b"a\n" * 20).splitlines(True)
364
 
        this_text = (b"a\n" * 10 + b"b\n" * 10).splitlines(True)
365
 
        other_text = (b"a\n" * 10 + b"c\n" + b"b\n" *
366
 
                      8 + b"c\n").splitlines(True)
367
 
        m3 = merge3.Merge3(base_text, other_text, this_text)
368
 
        m_lines = m3.merge_lines(b'OTHER', b'THIS', reprocess=True,
369
 
                                 base_marker=b'|||||||')
370
 
        self.assertRaises(merge3.CantReprocessAndShowBase, list, m_lines)
371
 
 
372
 
    def test_binary(self):
373
 
        self.assertRaises(BinaryFile, merge3.Merge3, [b'\x00'], [b'a'], [b'b'])
374
 
 
375
 
    def test_dos_text(self):
376
 
        base_text = b'a\r\n'
377
 
        this_text = b'b\r\n'
378
 
        other_text = b'c\r\n'
379
 
        m3 = merge3.Merge3(base_text.splitlines(True),
380
 
                           other_text.splitlines(True),
381
 
                           this_text.splitlines(True))
382
 
        m_lines = m3.merge_lines(b'OTHER', b'THIS')
383
 
        self.assertEqual(b'<<<<<<< OTHER\r\nc\r\n=======\r\nb\r\n'
384
 
                         b'>>>>>>> THIS\r\n'.splitlines(True), list(m_lines))
385
 
 
386
 
    def test_mac_text(self):
387
 
        base_text = b'a\r'
388
 
        this_text = b'b\r'
389
 
        other_text = b'c\r'
390
 
        m3 = merge3.Merge3(base_text.splitlines(True),
391
 
                           other_text.splitlines(True),
392
 
                           this_text.splitlines(True))
393
 
        m_lines = m3.merge_lines(b'OTHER', b'THIS')
394
 
        self.assertEqual(b'<<<<<<< OTHER\rc\r=======\rb\r'
395
 
                         b'>>>>>>> THIS\r'.splitlines(True), list(m_lines))
396
 
 
397
 
    def test_merge3_cherrypick(self):
398
 
        base_text = b"a\nb\n"
399
 
        this_text = b"a\n"
400
 
        other_text = b"a\nb\nc\n"
401
 
        # When cherrypicking, lines in base are not part of the conflict
402
 
        m3 = merge3.Merge3(base_text.splitlines(True),
403
 
                           this_text.splitlines(True),
404
 
                           other_text.splitlines(True), is_cherrypick=True)
405
 
        m_lines = m3.merge_lines()
406
 
        self.assertEqualDiff(b'a\n<<<<<<<\n=======\nc\n>>>>>>>\n',
407
 
                             b''.join(m_lines))
408
 
 
409
 
        # This is not symmetric
410
 
        m3 = merge3.Merge3(base_text.splitlines(True),
411
 
                           other_text.splitlines(True),
412
 
                           this_text.splitlines(True), is_cherrypick=True)
413
 
        m_lines = m3.merge_lines()
414
 
        self.assertEqualDiff(b'a\n<<<<<<<\nb\nc\n=======\n>>>>>>>\n',
415
 
                             b''.join(m_lines))
416
 
 
417
 
    def test_merge3_cherrypick_w_mixed(self):
418
 
        base_text = b'a\nb\nc\nd\ne\n'
419
 
        this_text = b'a\nb\nq\n'
420
 
        other_text = b'a\nb\nc\nd\nf\ne\ng\n'
421
 
        # When cherrypicking, lines in base are not part of the conflict
422
 
        m3 = merge3.Merge3(base_text.splitlines(True),
423
 
                           this_text.splitlines(True),
424
 
                           other_text.splitlines(True), is_cherrypick=True)
425
 
        m_lines = m3.merge_lines()
426
 
        self.assertEqualDiff(b'a\n'
427
 
                             b'b\n'
428
 
                             b'<<<<<<<\n'
429
 
                             b'q\n'
430
 
                             b'=======\n'
431
 
                             b'f\n'
432
 
                             b'>>>>>>>\n'
433
 
                             b'<<<<<<<\n'
434
 
                             b'=======\n'
435
 
                             b'g\n'
436
 
                             b'>>>>>>>\n',
437
 
                             b''.join(m_lines))
438
 
 
439
 
    def test_allow_objects(self):
440
 
        """Objects other than strs may be used with Merge3 when
441
 
        allow_objects=True.
442
 
 
443
 
        merge_groups and merge_regions work with non-str input.  Methods that
444
 
        return lines like merge_lines fail.
445
 
        """
446
 
        base = [(x, x) for x in 'abcde']
447
 
        a = [(x, x) for x in 'abcdef']
448
 
        b = [(x, x) for x in 'Zabcde']
449
 
        m3 = merge3.Merge3(base, a, b, allow_objects=True)
450
 
        self.assertEqual(
451
 
            [('b', 0, 1),
452
 
             ('unchanged', 0, 5),
453
 
             ('a', 5, 6)],
454
 
            list(m3.merge_regions()))
455
 
        self.assertEqual(
456
 
            [('b', [('Z', 'Z')]),
457
 
             ('unchanged', [(x, x) for x in 'abcde']),
458
 
             ('a', [('f', 'f')])],
459
 
            list(m3.merge_groups()))
 
320
        base_text = ("a\n" * 20).splitlines(True)
 
321
        this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
 
322
        other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True)
 
323
        m3 = Merge3(base_text, other_text, this_text)
 
324
        m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True, 
 
325
                                 base_marker='|||||||')
 
326
        self.assertRaises(CantReprocessAndShowBase, list, m_lines)