~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-05-29 23:15:16 UTC
  • mfrom: (1711.2.25 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060529231516-cad98b5042ea75f3
(jam) Updates to PatienceDiff for performance, and other cleanups.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006 Canonical Development 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
 
1
17
from cStringIO import StringIO
2
18
 
3
19
from bzrlib.diff import internal_diff
4
20
from bzrlib.errors import BinaryFile
5
 
from bzrlib.patiencediff import (recurse_matches, SequenceMatcher, unique_lcs,
6
 
                                 unified_diff, unified_diff_files)
 
21
import bzrlib.patiencediff
7
22
from bzrlib.tests import TestCase, TestCaseInTempDir
8
23
 
9
24
 
62
77
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
63
78
 
64
79
 
65
 
class TestCDVDiffLib(TestCase):
 
80
class TestPatienceDiffLib(TestCase):
66
81
 
67
82
    def test_unique_lcs(self):
 
83
        unique_lcs = bzrlib.patiencediff.unique_lcs
68
84
        self.assertEquals(unique_lcs('', ''), [])
69
85
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
70
86
        self.assertEquals(unique_lcs('a', 'b'), [])
78
94
    def test_recurse_matches(self):
79
95
        def test_one(a, b, matches):
80
96
            test_matches = []
81
 
            recurse_matches(a, b, len(a), len(b), test_matches, 10)
 
97
            bzrlib.patiencediff.recurse_matches(a, b, 0, 0, len(a), len(b),
 
98
                test_matches, 10)
82
99
            self.assertEquals(test_matches, matches)
83
100
 
84
 
        test_one(['a', None, 'b', None, 'c'], ['a', 'a', 'b', 'c', 'c'],
 
101
        test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
85
102
                 [(0, 0), (2, 2), (4, 4)])
86
103
        test_one(['a', 'c', 'b', 'a', 'c'], ['a', 'b', 'c'],
87
104
                 [(0, 0), (2, 1), (4, 2)])
97
114
        test_one('aBccDe', 'abccde', [(0,0), (5,5)])
98
115
 
99
116
    def test_matching_blocks(self):
100
 
        def chk_blocks(a, b, matching):
 
117
        def chk_blocks(a, b, expected_blocks):
101
118
            # difflib always adds a signature of the total
102
119
            # length, with no matching entries at the end
103
 
            s = SequenceMatcher(None, a, b)
 
120
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
104
121
            blocks = s.get_matching_blocks()
105
 
            x = blocks.pop()
106
 
            self.assertEquals(x, (len(a), len(b), 0))
107
 
            self.assertEquals(matching, blocks)
 
122
            self.assertEquals((len(a), len(b), 0), blocks[-1])
 
123
            self.assertEquals(expected_blocks, blocks[:-1])
108
124
 
109
125
        # Some basic matching tests
110
126
        chk_blocks('', '', [])
133
149
                    'how are you today?\n'],
134
150
                [(0, 0, 1), (2, 1, 1)])
135
151
 
136
 
        chk_blocks('aBccDe', 'abccde', [(0,0,1), (2,2,2), (5,5,1)])
137
 
 
138
 
        chk_blocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
139
 
                                              (5,5,2), (8,8,1)])
140
 
 
141
 
        chk_blocks('abbabbXd', 'cabbabxd', [(0,1,5), (7,7,1)])
142
 
        chk_blocks('abbabbbb', 'cabbabbc', [(0,1,6)])
143
 
        chk_blocks('bbbbbbbb', 'cbbbbbbc', [(0,1,6)])
 
152
        # non unique lines surrounded by non-matching lines
 
153
        # won't be found
 
154
        chk_blocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
 
155
 
 
156
        # But they only need to be locally unique
 
157
        chk_blocks('aBcDec', 'abcdec', [(0,0,1), (2,2,1), (4,4,2)])
 
158
 
 
159
        # non unique blocks won't be matched
 
160
        chk_blocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (8,8,1)])
 
161
 
 
162
        # but locally unique ones will
 
163
        chk_blocks('aBcdEeXcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
 
164
                                              (5,4,1), (7,5,2), (10,8,1)])
 
165
 
 
166
        chk_blocks('abbabbXd', 'cabbabxd', [(7,7,1)])
 
167
        chk_blocks('abbabbbb', 'cabbabbc', [])
 
168
        chk_blocks('bbbbbbbb', 'cbbbbbbc', [])
144
169
 
145
170
    def test_opcodes(self):
146
 
        def chk_ops(a, b, codes):
147
 
            s = SequenceMatcher(None, a, b)
148
 
            self.assertEquals(codes, s.get_opcodes())
 
171
        def chk_ops(a, b, expected_codes):
 
172
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
 
173
            self.assertEquals(expected_codes, s.get_opcodes())
149
174
 
150
175
        chk_ops('', '', [])
151
176
        chk_ops([], [], [])
185
210
                , 'how are you today?\n'],
186
211
                [('equal',  0,1, 0,1),
187
212
                 ('delete', 1,2, 1,1),
188
 
                 ('equal',  2,3, 1,2)
 
213
                 ('equal',  2,3, 1,2),
189
214
                ])
190
215
        chk_ops('aBccDe', 'abccde', 
191
216
                [('equal',   0,1, 0,1),
 
217
                 ('replace', 1,5, 1,5),
 
218
                 ('equal',   5,6, 5,6),
 
219
                ])
 
220
        chk_ops('aBcDec', 'abcdec', 
 
221
                [('equal',   0,1, 0,1),
192
222
                 ('replace', 1,2, 1,2),
193
 
                 ('equal',   2,4, 2,4),
194
 
                 ('replace', 4,5, 4,5),
195
 
                 ('equal',   5,6, 5,6)
 
223
                 ('equal',   2,3, 2,3),
 
224
                 ('replace', 3,4, 3,4),
 
225
                 ('equal',   4,6, 4,6),
196
226
                ])
197
227
        chk_ops('aBcdEcdFg', 'abcdecdfg', 
198
228
                [('equal',   0,1, 0,1),
199
 
                 ('replace', 1,2, 1,2),
200
 
                 ('equal',   2,4, 2,4),
201
 
                 ('replace', 4,5, 4,5),
202
 
                 ('equal',   5,7, 5,7),
203
 
                 ('replace', 7,8, 7,8),
 
229
                 ('replace', 1,8, 1,8),
204
230
                 ('equal',   8,9, 8,9)
205
231
                ])
 
232
        chk_ops('aBcdEeXcdFg', 'abcdecdfg', 
 
233
                [('equal',   0,1, 0,1),
 
234
                 ('replace', 1,2, 1,2),
 
235
                 ('equal',   2,4, 2,4),
 
236
                 ('delete', 4,5, 4,4),
 
237
                 ('equal',   5,6, 4,5),
 
238
                 ('delete', 6,7, 5,5),
 
239
                 ('equal',   7,9, 5,7),
 
240
                 ('replace', 9,10, 7,8),
 
241
                 ('equal',   10,11, 8,9)
 
242
                ])
206
243
 
207
244
    def test_multiple_ranges(self):
208
245
        # There was an earlier bug where we used a bad set of ranges,
209
246
        # this triggers that specific bug, to make sure it doesn't regress
210
 
        def chk_blocks(a, b, matching):
 
247
        def chk_blocks(a, b, expected_blocks):
211
248
            # difflib always adds a signature of the total
212
249
            # length, with no matching entries at the end
213
 
            s = SequenceMatcher(None, a, b)
 
250
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
214
251
            blocks = s.get_matching_blocks()
215
252
            x = blocks.pop()
216
253
            self.assertEquals(x, (len(a), len(b), 0))
217
 
            self.assertEquals(matching, blocks)
 
254
            self.assertEquals(expected_blocks, blocks)
218
255
 
219
256
        chk_blocks('abcdefghijklmnop'
220
257
                 , 'abcXghiYZQRSTUVWXYZijklmnop'
222
259
 
223
260
        chk_blocks('ABCd efghIjk  L'
224
261
                 , 'AxyzBCn mo pqrstuvwI1 2  L'
225
 
                 , [(0,0,1), (1, 4, 2), (4, 7, 1), (9, 19, 1), (12, 23, 3)])
 
262
                 , [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
226
263
 
 
264
        # These are rot13 code snippets.
227
265
        chk_blocks('''\
228
 
    get added when you add a file in the directory.
229
 
    """
230
 
    takes_args = ['file*']
231
 
    takes_options = ['no-recurse']
232
 
    
233
 
    def run(self, file_list, no_recurse=False):
234
 
        from bzrlib.add import smart_add, add_reporter_print, add_reporter_null
235
 
        if is_quiet():
236
 
            reporter = add_reporter_null
237
 
        else:
238
 
            reporter = add_reporter_print
239
 
        smart_add(file_list, not no_recurse, reporter)
240
 
 
241
 
 
242
 
class cmd_mkdir(Command):
243
 
'''.splitlines(True)
244
 
, '''\
245
 
    get added when you add a file in the directory.
246
 
 
247
 
    --dry-run will show which files would be added, but not actually 
248
 
    add them.
249
 
    """
250
 
    takes_args = ['file*']
251
 
    takes_options = ['no-recurse', 'dry-run']
252
 
 
253
 
    def run(self, file_list, no_recurse=False, dry_run=False):
254
 
        import bzrlib.add
255
 
 
256
 
        if dry_run:
257
 
            if is_quiet():
258
 
                # This is pointless, but I'd rather not raise an error
259
 
                action = bzrlib.add.add_action_null
260
 
            else:
261
 
                action = bzrlib.add.add_action_print
262
 
        elif is_quiet():
263
 
            action = bzrlib.add.add_action_add
264
 
        else:
265
 
            action = bzrlib.add.add_action_add_and_print
266
 
 
267
 
        bzrlib.add.smart_add(file_list, not no_recurse, action)
268
 
 
269
 
 
270
 
class cmd_mkdir(Command):
 
266
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
 
267
    """
 
268
    gnxrf_netf = ['svyr*']
 
269
    gnxrf_bcgvbaf = ['ab-erphefr']
 
270
  
 
271
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
 
272
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
 
273
        vs vf_dhvrg():
 
274
            ercbegre = nqq_ercbegre_ahyy
 
275
        ryfr:
 
276
            ercbegre = nqq_ercbegre_cevag
 
277
        fzneg_nqq(svyr_yvfg, abg ab_erphefr, ercbegre)
 
278
 
 
279
 
 
280
pynff pzq_zxqve(Pbzznaq):
 
281
'''.splitlines(True), '''\
 
282
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
 
283
 
 
284
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl 
 
285
    nqq gurz.
 
286
    """
 
287
    gnxrf_netf = ['svyr*']
 
288
    gnxrf_bcgvbaf = ['ab-erphefr', 'qel-eha']
 
289
 
 
290
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr, qel_eha=Snyfr):
 
291
        vzcbeg omeyvo.nqq
 
292
 
 
293
        vs qel_eha:
 
294
            vs vf_dhvrg():
 
295
                # Guvf vf cbvagyrff, ohg V'q engure abg envfr na reebe
 
296
                npgvba = omeyvo.nqq.nqq_npgvba_ahyy
 
297
            ryfr:
 
298
  npgvba = omeyvo.nqq.nqq_npgvba_cevag
 
299
        ryvs vf_dhvrg():
 
300
            npgvba = omeyvo.nqq.nqq_npgvba_nqq
 
301
        ryfr:
 
302
       npgvba = omeyvo.nqq.nqq_npgvba_nqq_naq_cevag
 
303
 
 
304
        omeyvo.nqq.fzneg_nqq(svyr_yvfg, abg ab_erphefr, npgvba)
 
305
 
 
306
 
 
307
pynff pzq_zxqve(Pbzznaq):
271
308
'''.splitlines(True)
272
309
, [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
273
310
 
274
 
    def test_cdv_unified_diff(self):
 
311
    def test_patience_unified_diff(self):
275
312
        txt_a = ['hello there\n',
276
313
                 'world\n',
277
314
                 'how are you today?\n']
278
315
        txt_b = ['hello there\n',
279
316
                 'how are you today?\n']
 
317
        unified_diff = bzrlib.patiencediff.unified_diff
 
318
        psm = bzrlib.patiencediff.PatienceSequenceMatcher
280
319
        self.assertEquals([ '---  \n',
281
320
                           '+++  \n',
282
321
                           '@@ -1,3 +1,2 @@\n',
284
323
                           '-world\n',
285
324
                           ' how are you today?\n'
286
325
                          ]
287
 
                          , list(unified_diff(txt_a, txt_b
288
 
                                        , sequencematcher=SequenceMatcher)))
 
326
                          , list(unified_diff(txt_a, txt_b,
 
327
                                 sequencematcher=psm)))
289
328
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
290
329
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
291
330
        # This is the result with LongestCommonSubstring matching
304
343
                           ' e\n',
305
344
                           ' f\n']
306
345
                          , list(unified_diff(txt_a, txt_b)))
307
 
        # And the cdv diff
 
346
        # And the patience diff
308
347
        self.assertEquals(['---  \n',
309
348
                           '+++  \n',
310
349
                           '@@ -4,6 +4,11 @@\n',
321
360
                           ' i\n',
322
361
                          ]
323
362
                          , list(unified_diff(txt_a, txt_b,
324
 
                                 sequencematcher=SequenceMatcher)))
325
 
 
326
 
 
327
 
class TestCDVDiffLibFiles(TestCaseInTempDir):
328
 
 
329
 
    def test_cdv_unified_diff_files(self):
 
363
                                 sequencematcher=psm)))
 
364
 
 
365
 
 
366
class TestPatienceDiffLibFiles(TestCaseInTempDir):
 
367
 
 
368
    def test_patience_unified_diff_files(self):
330
369
        txt_a = ['hello there\n',
331
370
                 'world\n',
332
371
                 'how are you today?\n']
335
374
        open('a1', 'wb').writelines(txt_a)
336
375
        open('b1', 'wb').writelines(txt_b)
337
376
 
 
377
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
 
378
        psm = bzrlib.patiencediff.PatienceSequenceMatcher
338
379
        self.assertEquals(['--- a1 \n',
339
380
                           '+++ b1 \n',
340
381
                           '@@ -1,3 +1,2 @@\n',
343
384
                           ' how are you today?\n',
344
385
                          ]
345
386
                          , list(unified_diff_files('a1', 'b1',
346
 
                                 sequencematcher=SequenceMatcher)))
 
387
                                 sequencematcher=psm)))
347
388
 
348
389
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
349
390
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
367
408
                           ' f\n']
368
409
                          , list(unified_diff_files('a2', 'b2')))
369
410
 
370
 
        # And the cdv diff
 
411
        # And the patience diff
371
412
        self.assertEquals(['--- a2 \n',
372
413
                           '+++ b2 \n',
373
414
                           '@@ -4,6 +4,11 @@\n',
384
425
                           ' i\n',
385
426
                          ]
386
427
                          , list(unified_diff_files('a2', 'b2',
387
 
                                 sequencematcher=SequenceMatcher)))
 
428
                                 sequencematcher=psm)))