~bzr-pqm/bzr/bzr.dev

821 by Martin Pool
- start code for built-in diff3-style resolve
1
# Copyright (C) 2004, 2005 by Canonical Ltd
2
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
13
# You should have received a copy of the GNU General Public License
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
831 by Martin Pool
- add merge3 test case from Lao-Tzu
21
22
23
24
821 by Martin Pool
- start code for built-in diff3-style resolve
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'])
31
32
        self.assertEquals(m3.find_unconflicted(),
33
                          [(0, 2)])
34
822 by Martin Pool
- Renamed merge3 test suite for easier access.
35
        self.assertEquals(list(m3.find_sync_regions()),
824 by Martin Pool
- Merge3.find_sync_regions yields just a 6-tuple, not a tuple of tuples
36
                          [(0, 2,
37
                            0, 2,
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
38
                            0, 2),
39
                           (2,2, 2,2, 2,2)])
40
41
        self.assertEquals(list(m3.merge_regions()),
42
                          [('unchanged', 0, 2)])
43
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
44
        self.assertEquals(list(m3.merge_groups()),
45
                          [('unchanged', ['aaa', 'bbb'])])
46
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
47
48
class FrontInsert(TestBase):
49
    def runTest(self):
50
        m3 = Merge3(['zz'],
51
                    ['aaa', 'bbb', 'zz'],
52
                    ['zz'])
53
54
        # todo: should use a sentinal at end as from get_matching_blocks
55
        # to match without zz
56
        self.assertEquals(list(m3.find_sync_regions()),
57
                          [(0,1, 2,3, 0,1),
58
                           (1,1, 3,3, 1,1),])
59
60
        self.assertEquals(list(m3.merge_regions()),
61
                          [('a', 0, 2),
62
                           ('unchanged', 0, 1)])
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
63
64
        self.assertEquals(list(m3.merge_groups()),
65
                          [('a', ['aaa', 'bbb']),
66
                           ('unchanged', ['zz'])])
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
67
        
68
    
69
70
class NullInsert(TestBase):
71
    def runTest(self):
72
        m3 = Merge3([],
73
                    ['aaa', 'bbb'],
74
                    [])
75
76
        # todo: should use a sentinal at end as from get_matching_blocks
77
        # to match without zz
78
        self.assertEquals(list(m3.find_sync_regions()),
79
                          [(0,0, 2,2, 0,0)])
80
81
        self.assertEquals(list(m3.merge_regions()),
82
                          [('a', 0, 2)])
828 by Martin Pool
- code to represent merges in regular text conflict form
83
84
        self.assertEquals(list(m3.merge_lines()),
85
                          ['aaa', 'bbb'])
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
86
        
821 by Martin Pool
- start code for built-in diff3-style resolve
87
    
88
822 by Martin Pool
- Renamed merge3 test suite for easier access.
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'])
95
96
        self.assertEquals(m3.find_unconflicted(),
97
                          [(0, 1), (1, 2)])
98
99
        self.assertEquals(list(m3.find_sync_regions()),
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
100
                          [(0,1, 0,1, 0,1),
101
                           (1,2, 2,3, 1,2),
102
                           (2,2, 3,3, 2,2),])
103
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
104
        self.assertEquals(list(m3.merge_regions()),
105
                          [('unchanged', 0, 1),
106
                           ('a', 1, 2),
107
                           ('unchanged', 1, 2),])
108
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
109
822 by Martin Pool
- Renamed merge3 test suite for easier access.
110
836 by Martin Pool
- more merge tests from john
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'])
143
144
        ml = m3.merge_lines(name_a='a',
145
                            name_b='b',
146
                            start_marker='<<',
147
                            mid_marker='--',
148
                            end_marker='>>')
149
        self.assertEquals(''.join(ml),
150
'''\
151
aaa
152
bbb
153
<< a
154
222
155
--
156
333
157
>> b
158
''')
159
160
830 by Martin Pool
- handle chunks which differ from the base but agree
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'])
166
836 by Martin Pool
- more merge tests from john
167
        ml = m3.merge_lines(name_a='a',
168
                            name_b='b',
169
                            start_marker='<<',
170
                            mid_marker='--',
171
                            end_marker='>>')
830 by Martin Pool
- handle chunks which differ from the base but agree
172
        self.assertEquals(''.join(m3.merge_lines()),
173
                          'aaa\n222\nbbb\n')
174
175
822 by Martin Pool
- Renamed merge3 test suite for easier access.
176
836 by Martin Pool
- more merge tests from john
177
821 by Martin Pool
- start code for built-in diff3-style resolve
178
class InsertClash(TestBase):
179
    """Both try to insert lines in the same place."""
180
    def runTest(self):
829 by Martin Pool
- More merge3 cvs-form stuff
181
        m3 = Merge3(['aaa\n', 'bbb\n'],
182
                    ['aaa\n', '111\n', 'bbb\n'],
183
                    ['aaa\n', '222\n', 'bbb\n'])
821 by Martin Pool
- start code for built-in diff3-style resolve
184
185
        self.assertEquals(m3.find_unconflicted(),
186
                          [(0, 1), (1, 2)])
187
822 by Martin Pool
- Renamed merge3 test suite for easier access.
188
        self.assertEquals(list(m3.find_sync_regions()),
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
189
                          [(0,1, 0,1, 0,1),
190
                           (1,2, 2,3, 2,3),
191
                           (2,2, 3,3, 3,3),])
821 by Martin Pool
- start code for built-in diff3-style resolve
192
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
193
        self.assertEquals(list(m3.merge_regions()),
194
                          [('unchanged', 0,1),
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
195
                           ('conflict', 1,1, 1,2, 1,2),
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
196
                           ('unchanged', 1,2)])
197
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
198
        self.assertEquals(list(m3.merge_groups()),
829 by Martin Pool
- More merge3 cvs-form stuff
199
                          [('unchanged', ['aaa\n']),
200
                           ('conflict', [], ['111\n'], ['222\n']),
201
                           ('unchanged', ['bbb\n']),
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
202
                           ])
203
829 by Martin Pool
- More merge3 cvs-form stuff
204
        ml = m3.merge_lines(name_a='a',
205
                            name_b='b',
206
                            start_marker='<<',
207
                            mid_marker='--',
208
                            end_marker='>>')
209
        self.assertEquals(''.join(ml),
210
'''aaa
211
<< a
212
111
213
--
214
222
215
>> b
216
bbb
217
''')
828 by Martin Pool
- code to represent merges in regular text conflict form
218
821 by Martin Pool
- start code for built-in diff3-style resolve
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'])
227
228
        self.assertEquals(m3.find_unconflicted(),
229
                          [(0, 1), (2, 3)])
230
822 by Martin Pool
- Renamed merge3 test suite for easier access.
231
        self.assertEquals(list(m3.find_sync_regions()),
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
232
                          [(0,1, 0,1, 0,1),
233
                           (2,3, 2,3, 2,3),
234
                           (3,3, 3,3, 3,3),])
822 by Martin Pool
- Renamed merge3 test suite for easier access.
235
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'])
244
245
        self.assertEquals(m3.find_unconflicted(),
246
                          [(0, 1), (3, 4)])
247
248
249
        self.assertEquals(list(m3.find_sync_regions()),
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
250
                          [(0,1, 0,1, 0,1),
251
                           (3,4, 4,5, 5,6),
252
                           (4,4, 5,5, 6,6),])
822 by Martin Pool
- Renamed merge3 test suite for easier access.
253
254
        
821 by Martin Pool
- start code for built-in diff3-style resolve
255
        
831 by Martin Pool
- add merge3 test case from Lao-Tzu
256
257
258
259
260
def split_lines(t):
261
    from cStringIO import StringIO
262
    return StringIO(t).readlines()
263
264
835 by Martin Pool
doc
265
266
############################################################
267
# test case from the gnu diffutils manual
268
831 by Martin Pool
- add merge3 test case from Lao-Tzu
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)
341
        ml = list(m3.merge_lines('LAO', 'TAO'))
342
        self.log('merge result:')
343
        self.log(''.join(ml))
344
        self.assertEquals(ml, MERGED_RESULT)
843 by Martin Pool
- workaround for flaky TestLoader in python2.3
345
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
    ]