~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_merge3.py

  • Committer: Martin Packman
  • Date: 2011-11-17 13:45:49 UTC
  • mto: This revision was merged to the branch mainline in revision 6271.
  • Revision ID: martin.packman@canonical.com-20111117134549-080e1fhtrzoicexg
Only assert FileExists path in test_transform directory clash tests to avoid stringification fallout

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-2011 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.selftest import InTempDir, TestBase
19
 
from bzrlib.merge3 import Merge3
20
 
 
21
 
 
22
 
 
23
 
 
24
 
 
25
 
class NoChanges(TestBase):
26
 
    """No conflicts because nothing changed"""
27
 
    def runTest(self):
28
 
        m3 = Merge3(['aaa', 'bbb'],
29
 
                    ['aaa', 'bbb'],
30
 
                    ['aaa', 'bbb'])
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
 
 
18
from bzrlib import (
 
19
    merge3,
 
20
    tests,
 
21
    )
 
22
from bzrlib.errors import CantReprocessAndShowBase, BinaryFile
 
23
 
 
24
def split_lines(t):
 
25
    from cStringIO import StringIO
 
26
    return StringIO(t).readlines()
 
27
 
 
28
############################################################
 
29
# test case data from the gnu diffutils manual
 
30
# common base
 
31
TZU = split_lines("""     The Nameless is the origin of Heaven and Earth;
 
32
     The named is the mother of all things.
 
33
 
 
34
     Therefore let there always be non-being,
 
35
       so we may see their subtlety,
 
36
     And let there always be being,
 
37
       so we may see their outcome.
 
38
     The two are the same,
 
39
     But after they are produced,
 
40
       they have different names.
 
41
     They both may be called deep and profound.
 
42
     Deeper and more profound,
 
43
     The door of all subtleties!
 
44
""")
 
45
 
 
46
LAO = split_lines("""     The Way that can be told of is not the eternal Way;
 
47
     The name that can be named is not the eternal name.
 
48
     The Nameless is the origin of Heaven and Earth;
 
49
     The Named is the mother of all things.
 
50
     Therefore let there always be non-being,
 
51
       so we may see their subtlety,
 
52
     And let there always be being,
 
53
       so we may see their outcome.
 
54
     The two are the same,
 
55
     But after they are produced,
 
56
       they have different names.
 
57
""")
 
58
 
 
59
 
 
60
TAO = split_lines("""     The Way that can be told of is not the eternal Way;
 
61
     The name that can be named is not the eternal name.
 
62
     The Nameless is the origin of Heaven and Earth;
 
63
     The named is the mother of all things.
 
64
 
 
65
     Therefore let there always be non-being,
 
66
       so we may see their subtlety,
 
67
     And let there always be being,
 
68
       so we may see their result.
 
69
     The two are the same,
 
70
     But after they are produced,
 
71
       they have different names.
 
72
 
 
73
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
 
74
 
 
75
""")
 
76
 
 
77
MERGED_RESULT = split_lines("""     The Way that can be told of is not the eternal Way;
 
78
     The name that can be named is not the eternal name.
 
79
     The Nameless is the origin of Heaven and Earth;
 
80
     The Named is the mother of all things.
 
81
     Therefore let there always be non-being,
 
82
       so we may see their subtlety,
 
83
     And let there always be being,
 
84
       so we may see their result.
 
85
     The two are the same,
 
86
     But after they are produced,
 
87
       they have different names.
 
88
<<<<<<< LAO
 
89
=======
 
90
 
 
91
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
 
92
 
 
93
>>>>>>> TAO
 
94
""")
 
95
 
 
96
class TestMerge3(tests.TestCase):
 
97
 
 
98
    def test_no_changes(self):
 
99
        """No conflicts because nothing changed"""
 
100
        m3 = merge3.Merge3(['aaa', 'bbb'],
 
101
                           ['aaa', 'bbb'],
 
102
                           ['aaa', 'bbb'])
31
103
 
32
104
        self.assertEquals(m3.find_unconflicted(),
33
105
                          [(0, 2)])
44
116
        self.assertEquals(list(m3.merge_groups()),
45
117
                          [('unchanged', ['aaa', 'bbb'])])
46
118
 
47
 
 
48
 
class FrontInsert(TestBase):
49
 
    def runTest(self):
50
 
        m3 = Merge3(['zz'],
51
 
                    ['aaa', 'bbb', 'zz'],
52
 
                    ['zz'])
 
119
    def test_front_insert(self):
 
120
        m3 = merge3.Merge3(['zz'],
 
121
                           ['aaa', 'bbb', 'zz'],
 
122
                           ['zz'])
53
123
 
54
124
        # todo: should use a sentinal at end as from get_matching_blocks
55
125
        # to match without zz
64
134
        self.assertEquals(list(m3.merge_groups()),
65
135
                          [('a', ['aaa', 'bbb']),
66
136
                           ('unchanged', ['zz'])])
67
 
        
68
 
    
69
 
 
70
 
class NullInsert(TestBase):
71
 
    def runTest(self):
72
 
        m3 = Merge3([],
73
 
                    ['aaa', 'bbb'],
74
 
                    [])
75
 
 
 
137
 
 
138
    def test_null_insert(self):
 
139
        m3 = merge3.Merge3([],
 
140
                           ['aaa', 'bbb'],
 
141
                           [])
76
142
        # todo: should use a sentinal at end as from get_matching_blocks
77
143
        # to match without zz
78
144
        self.assertEquals(list(m3.find_sync_regions()),
83
149
 
84
150
        self.assertEquals(list(m3.merge_lines()),
85
151
                          ['aaa', 'bbb'])
86
 
        
87
 
    
88
152
 
89
 
class NoConflicts(TestBase):
90
 
    """No conflicts because only one side changed"""
91
 
    def runTest(self):
92
 
        m3 = Merge3(['aaa', 'bbb'],
93
 
                    ['aaa', '111', 'bbb'],
94
 
                    ['aaa', 'bbb'])
 
153
    def test_no_conflicts(self):
 
154
        """No conflicts because only one side changed"""
 
155
        m3 = merge3.Merge3(['aaa', 'bbb'],
 
156
                           ['aaa', '111', 'bbb'],
 
157
                           ['aaa', 'bbb'])
95
158
 
96
159
        self.assertEquals(m3.find_unconflicted(),
97
160
                          [(0, 1), (1, 2)])
106
169
                           ('a', 1, 2),
107
170
                           ('unchanged', 1, 2),])
108
171
 
109
 
 
110
 
 
111
 
class AppendA(TestBase):
112
 
    def runTest(self):
113
 
        m3 = Merge3(['aaa\n', 'bbb\n'],
114
 
                    ['aaa\n', 'bbb\n', '222\n'],
115
 
                    ['aaa\n', 'bbb\n'])
116
 
 
117
 
        self.assertEquals(''.join(m3.merge_lines()),
118
 
                          'aaa\nbbb\n222\n')
119
 
 
120
 
class AppendB(TestBase):
121
 
    def runTest(self):
122
 
        m3 = Merge3(['aaa\n', 'bbb\n'],
123
 
                    ['aaa\n', 'bbb\n'],
124
 
                    ['aaa\n', 'bbb\n', '222\n'])
125
 
 
126
 
        self.assertEquals(''.join(m3.merge_lines()),
127
 
                          'aaa\nbbb\n222\n')
128
 
 
129
 
class AppendAgreement(TestBase):
130
 
    def runTest(self):
131
 
        m3 = Merge3(['aaa\n', 'bbb\n'],
132
 
                    ['aaa\n', 'bbb\n', '222\n'],
133
 
                    ['aaa\n', 'bbb\n', '222\n'])
134
 
 
135
 
        self.assertEquals(''.join(m3.merge_lines()),
136
 
                          'aaa\nbbb\n222\n')
137
 
 
138
 
class AppendClash(TestBase):
139
 
    def runTest(self):
140
 
        m3 = Merge3(['aaa\n', 'bbb\n'],
141
 
                    ['aaa\n', 'bbb\n', '222\n'],
142
 
                    ['aaa\n', 'bbb\n', '333\n'])
 
172
    def test_append_a(self):
 
173
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
 
174
                           ['aaa\n', 'bbb\n', '222\n'],
 
175
                           ['aaa\n', 'bbb\n'])
 
176
 
 
177
        self.assertEquals(''.join(m3.merge_lines()),
 
178
                          'aaa\nbbb\n222\n')
 
179
 
 
180
    def test_append_b(self):
 
181
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
 
182
                           ['aaa\n', 'bbb\n'],
 
183
                           ['aaa\n', 'bbb\n', '222\n'])
 
184
 
 
185
        self.assertEquals(''.join(m3.merge_lines()),
 
186
                          'aaa\nbbb\n222\n')
 
187
 
 
188
    def test_append_agreement(self):
 
189
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
 
190
                           ['aaa\n', 'bbb\n', '222\n'],
 
191
                           ['aaa\n', 'bbb\n', '222\n'])
 
192
 
 
193
        self.assertEquals(''.join(m3.merge_lines()),
 
194
                          'aaa\nbbb\n222\n')
 
195
 
 
196
    def test_append_clash(self):
 
197
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
 
198
                           ['aaa\n', 'bbb\n', '222\n'],
 
199
                           ['aaa\n', 'bbb\n', '333\n'])
143
200
 
144
201
        ml = m3.merge_lines(name_a='a',
145
202
                            name_b='b',
157
214
>> b
158
215
''')
159
216
 
160
 
 
161
 
class InsertAgreement(TestBase):
162
 
    def runTest(self):
163
 
        m3 = Merge3(['aaa\n', 'bbb\n'],
164
 
                    ['aaa\n', '222\n', 'bbb\n'],
165
 
                    ['aaa\n', '222\n', 'bbb\n'])
 
217
    def test_insert_agreement(self):
 
218
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
 
219
                           ['aaa\n', '222\n', 'bbb\n'],
 
220
                           ['aaa\n', '222\n', 'bbb\n'])
166
221
 
167
222
        ml = m3.merge_lines(name_a='a',
168
223
                            name_b='b',
169
224
                            start_marker='<<',
170
225
                            mid_marker='--',
171
226
                            end_marker='>>')
172
 
        self.assertEquals(''.join(m3.merge_lines()),
173
 
                          'aaa\n222\nbbb\n')
174
 
 
175
 
 
176
 
 
177
 
 
178
 
class InsertClash(TestBase):
179
 
    """Both try to insert lines in the same place."""
180
 
    def runTest(self):
181
 
        m3 = Merge3(['aaa\n', 'bbb\n'],
182
 
                    ['aaa\n', '111\n', 'bbb\n'],
183
 
                    ['aaa\n', '222\n', 'bbb\n'])
 
227
        self.assertEquals(''.join(ml), 'aaa\n222\nbbb\n')
 
228
 
 
229
 
 
230
    def test_insert_clash(self):
 
231
        """Both try to insert lines in the same place."""
 
232
        m3 = merge3.Merge3(['aaa\n', 'bbb\n'],
 
233
                           ['aaa\n', '111\n', 'bbb\n'],
 
234
                           ['aaa\n', '222\n', 'bbb\n'])
184
235
 
185
236
        self.assertEquals(m3.find_unconflicted(),
186
237
                          [(0, 1), (1, 2)])
216
267
bbb
217
268
''')
218
269
 
219
 
 
220
 
 
221
 
class ReplaceClash(TestBase):
222
 
    """Both try to insert lines in the same place."""
223
 
    def runTest(self):
224
 
        m3 = Merge3(['aaa', '000', 'bbb'],
225
 
                    ['aaa', '111', 'bbb'],
226
 
                    ['aaa', '222', 'bbb'])
 
270
    def test_replace_clash(self):
 
271
        """Both try to insert lines in the same place."""
 
272
        m3 = merge3.Merge3(['aaa', '000', 'bbb'],
 
273
                           ['aaa', '111', 'bbb'],
 
274
                           ['aaa', '222', 'bbb'])
227
275
 
228
276
        self.assertEquals(m3.find_unconflicted(),
229
277
                          [(0, 1), (2, 3)])
233
281
                           (2,3, 2,3, 2,3),
234
282
                           (3,3, 3,3, 3,3),])
235
283
 
236
 
 
237
 
 
238
 
class ReplaceMulti(TestBase):
239
 
    """Replacement with regions of different size."""
240
 
    def runTest(self):
241
 
        m3 = Merge3(['aaa', '000', '000', 'bbb'],
242
 
                    ['aaa', '111', '111', '111', 'bbb'],
243
 
                    ['aaa', '222', '222', '222', '222', 'bbb'])
 
284
    def test_replace_multi(self):
 
285
        """Replacement with regions of different size."""
 
286
        m3 = merge3.Merge3(['aaa', '000', '000', 'bbb'],
 
287
                           ['aaa', '111', '111', '111', 'bbb'],
 
288
                           ['aaa', '222', '222', '222', '222', 'bbb'])
244
289
 
245
290
        self.assertEquals(m3.find_unconflicted(),
246
291
                          [(0, 1), (3, 4)])
251
296
                           (3,4, 4,5, 5,6),
252
297
                           (4,4, 5,5, 6,6),])
253
298
 
254
 
        
255
 
        
256
 
 
257
 
 
258
 
 
259
 
 
260
 
def split_lines(t):
261
 
    from cStringIO import StringIO
262
 
    return StringIO(t).readlines()
263
 
 
264
 
 
265
 
 
266
 
############################################################
267
 
# test case from the gnu diffutils manual
268
 
 
269
 
# common base
270
 
TZU = split_lines("""     The Nameless is the origin of Heaven and Earth;
271
 
     The named is the mother of all things.
272
 
     
273
 
     Therefore let there always be non-being,
274
 
       so we may see their subtlety,
275
 
     And let there always be being,
276
 
       so we may see their outcome.
277
 
     The two are the same,
278
 
     But after they are produced,
279
 
       they have different names.
280
 
     They both may be called deep and profound.
281
 
     Deeper and more profound,
282
 
     The door of all subtleties!
283
 
""")
284
 
 
285
 
LAO = split_lines("""     The Way that can be told of is not the eternal Way;
286
 
     The name that can be named is not the eternal name.
287
 
     The Nameless is the origin of Heaven and Earth;
288
 
     The Named is the mother of all things.
289
 
     Therefore let there always be non-being,
290
 
       so we may see their subtlety,
291
 
     And let there always be being,
292
 
       so we may see their outcome.
293
 
     The two are the same,
294
 
     But after they are produced,
295
 
       they have different names.
296
 
""")
297
 
 
298
 
 
299
 
TAO = split_lines("""     The Way that can be told of is not the eternal Way;
300
 
     The name that can be named is not the eternal name.
301
 
     The Nameless is the origin of Heaven and Earth;
302
 
     The named is the mother of all things.
303
 
     
304
 
     Therefore let there always be non-being,
305
 
       so we may see their subtlety,
306
 
     And let there always be being,
307
 
       so we may see their result.
308
 
     The two are the same,
309
 
     But after they are produced,
310
 
       they have different names.
311
 
     
312
 
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
313
 
 
314
 
""")
315
 
 
316
 
MERGED_RESULT = split_lines("""     The Way that can be told of is not the eternal Way;
317
 
     The name that can be named is not the eternal name.
318
 
     The Nameless is the origin of Heaven and Earth;
319
 
     The Named is the mother of all things.
320
 
     Therefore let there always be non-being,
321
 
       so we may see their subtlety,
322
 
     And let there always be being,
323
 
       so we may see their result.
324
 
     The two are the same,
325
 
     But after they are produced,
326
 
       they have different names.
327
 
<<<<<<<< LAO
328
 
========
329
 
     
330
 
       -- The Way of Lao-Tzu, tr. Wing-tsit Chan
331
 
 
332
 
>>>>>>>> TAO
333
 
""")
334
 
 
335
 
 
336
 
 
337
 
class MergePoem(TestBase):
338
 
    """Test case from diff3 manual"""
339
 
    def runTest(self):
340
 
        m3 = Merge3(TZU, LAO, TAO)
 
299
    def test_merge_poem(self):
 
300
        """Test case from diff3 manual"""
 
301
        m3 = merge3.Merge3(TZU, LAO, TAO)
341
302
        ml = list(m3.merge_lines('LAO', 'TAO'))
342
303
        self.log('merge result:')
343
304
        self.log(''.join(ml))
344
305
        self.assertEquals(ml, MERGED_RESULT)
345
306
 
346
 
 
347
 
 
348
 
TEST_CLASSES = [
349
 
    NoChanges,
350
 
    FrontInsert,
351
 
    NullInsert,
352
 
    NoConflicts,
353
 
    AppendA,
354
 
    AppendB,
355
 
    AppendAgreement,
356
 
    AppendClash,
357
 
    InsertAgreement,
358
 
    InsertClash,
359
 
    ReplaceClash,
360
 
    ReplaceMulti,
361
 
    MergePoem,
362
 
    ]
 
307
    def test_minimal_conflicts_common(self):
 
308
        """Reprocessing"""
 
309
        base_text = ("a\n" * 20).splitlines(True)
 
310
        this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
 
311
        other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True)
 
312
        m3 = merge3.Merge3(base_text, other_text, this_text)
 
313
        m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
 
314
        merged_text = "".join(list(m_lines))
 
315
        optimal_text = ("a\n" * 10 + "<<<<<<< OTHER\nc\n"
 
316
            + 8* "b\n" + "c\n=======\n"
 
317
            + 10*"b\n" + ">>>>>>> THIS\n")
 
318
        self.assertEqualDiff(optimal_text, merged_text)
 
319
 
 
320
    def test_minimal_conflicts_unique(self):
 
321
        def add_newline(s):
 
322
            """Add a newline to each entry in the string"""
 
323
            return [(x+'\n') for x in s]
 
324
 
 
325
        base_text = add_newline("abcdefghijklm")
 
326
        this_text = add_newline("abcdefghijklmNOPQRSTUVWXYZ")
 
327
        other_text = add_newline("abcdefghijklm1OPQRSTUVWXY2")
 
328
        m3 = merge3.Merge3(base_text, other_text, this_text)
 
329
        m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
 
330
        merged_text = "".join(list(m_lines))
 
331
        optimal_text = ''.join(add_newline("abcdefghijklm")
 
332
            + ["<<<<<<< OTHER\n1\n=======\nN\n>>>>>>> THIS\n"]
 
333
            + add_newline('OPQRSTUVWXY')
 
334
            + ["<<<<<<< OTHER\n2\n=======\nZ\n>>>>>>> THIS\n"]
 
335
            )
 
336
        self.assertEqualDiff(optimal_text, merged_text)
 
337
 
 
338
    def test_minimal_conflicts_nonunique(self):
 
339
        def add_newline(s):
 
340
            """Add a newline to each entry in the string"""
 
341
            return [(x+'\n') for x in s]
 
342
 
 
343
        base_text = add_newline("abacddefgghij")
 
344
        this_text = add_newline("abacddefgghijkalmontfprz")
 
345
        other_text = add_newline("abacddefgghijknlmontfprd")
 
346
        m3 = merge3.Merge3(base_text, other_text, this_text)
 
347
        m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True)
 
348
        merged_text = "".join(list(m_lines))
 
349
        optimal_text = ''.join(add_newline("abacddefgghijk")
 
350
            + ["<<<<<<< OTHER\nn\n=======\na\n>>>>>>> THIS\n"]
 
351
            + add_newline('lmontfpr')
 
352
            + ["<<<<<<< OTHER\nd\n=======\nz\n>>>>>>> THIS\n"]
 
353
            )
 
354
        self.assertEqualDiff(optimal_text, merged_text)
 
355
 
 
356
    def test_reprocess_and_base(self):
 
357
        """Reprocessing and showing base breaks correctly"""
 
358
        base_text = ("a\n" * 20).splitlines(True)
 
359
        this_text = ("a\n"*10+"b\n" * 10).splitlines(True)
 
360
        other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True)
 
361
        m3 = merge3.Merge3(base_text, other_text, this_text)
 
362
        m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True,
 
363
                                 base_marker='|||||||')
 
364
        self.assertRaises(CantReprocessAndShowBase, list, m_lines)
 
365
 
 
366
    def test_binary(self):
 
367
        self.assertRaises(BinaryFile, merge3.Merge3, ['\x00'], ['a'], ['b'])
 
368
 
 
369
    def test_dos_text(self):
 
370
        base_text = 'a\r\n'
 
371
        this_text = 'b\r\n'
 
372
        other_text = 'c\r\n'
 
373
        m3 = merge3.Merge3(base_text.splitlines(True),
 
374
                           other_text.splitlines(True),
 
375
                           this_text.splitlines(True))
 
376
        m_lines = m3.merge_lines('OTHER', 'THIS')
 
377
        self.assertEqual('<<<<<<< OTHER\r\nc\r\n=======\r\nb\r\n'
 
378
            '>>>>>>> THIS\r\n'.splitlines(True), list(m_lines))
 
379
 
 
380
    def test_mac_text(self):
 
381
        base_text = 'a\r'
 
382
        this_text = 'b\r'
 
383
        other_text = 'c\r'
 
384
        m3 = merge3.Merge3(base_text.splitlines(True),
 
385
                           other_text.splitlines(True),
 
386
                           this_text.splitlines(True))
 
387
        m_lines = m3.merge_lines('OTHER', 'THIS')
 
388
        self.assertEqual('<<<<<<< OTHER\rc\r=======\rb\r'
 
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