~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: mbp at sourcefrog
  • Date: 2005-04-11 02:53:57 UTC
  • Revision ID: mbp@sourcefrog.net-20050411025357-af577721308648ae
- remove profiler temporary file when done

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 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
 
import os
18
 
from cStringIO import StringIO
19
 
import errno
20
 
import subprocess
21
 
from tempfile import TemporaryFile
22
 
 
23
 
from bzrlib.diff import internal_diff, external_diff, show_diff_trees
24
 
from bzrlib.errors import BinaryFile, NoDiff
25
 
import bzrlib.osutils as osutils
26
 
import bzrlib.patiencediff
27
 
import bzrlib._patiencediff_py
28
 
from bzrlib.tests import (Feature, TestCase, TestCaseWithTransport,
29
 
                          TestCaseInTempDir, TestSkipped)
30
 
 
31
 
 
32
 
class _CompiledPatienceDiffFeature(Feature):
33
 
 
34
 
    def _probe(self):
35
 
        try:
36
 
            import bzrlib._patiencediff_c
37
 
        except ImportError:
38
 
            return False
39
 
        return True
40
 
 
41
 
    def feature_name(self):
42
 
        return 'bzrlib._patiencediff_c'
43
 
 
44
 
CompiledPatienceDiffFeature = _CompiledPatienceDiffFeature()
45
 
 
46
 
 
47
 
class _UnicodeFilename(Feature):
48
 
    """Does the filesystem support Unicode filenames?"""
49
 
 
50
 
    def _probe(self):
51
 
        try:
52
 
            os.stat(u'\u03b1')
53
 
        except UnicodeEncodeError:
54
 
            return False
55
 
        except (IOError, OSError):
56
 
            # The filesystem allows the Unicode filename but the file doesn't
57
 
            # exist.
58
 
            return True
59
 
        else:
60
 
            # The filesystem allows the Unicode filename and the file exists,
61
 
            # for some reason.
62
 
            return True
63
 
 
64
 
UnicodeFilename = _UnicodeFilename()
65
 
 
66
 
 
67
 
class TestUnicodeFilename(TestCase):
68
 
 
69
 
    def test_probe_passes(self):
70
 
        """UnicodeFilename._probe passes."""
71
 
        # We can't test much more than that because the behaviour depends
72
 
        # on the platform.
73
 
        UnicodeFilename._probe()
74
 
        
75
 
 
76
 
def udiff_lines(old, new, allow_binary=False):
77
 
    output = StringIO()
78
 
    internal_diff('old', old, 'new', new, output, allow_binary)
79
 
    output.seek(0, 0)
80
 
    return output.readlines()
81
 
 
82
 
 
83
 
def external_udiff_lines(old, new, use_stringio=False):
84
 
    if use_stringio:
85
 
        # StringIO has no fileno, so it tests a different codepath
86
 
        output = StringIO()
87
 
    else:
88
 
        output = TemporaryFile()
89
 
    try:
90
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
91
 
    except NoDiff:
92
 
        raise TestSkipped('external "diff" not present to test')
93
 
    output.seek(0, 0)
94
 
    lines = output.readlines()
95
 
    output.close()
96
 
    return lines
97
 
 
98
 
 
99
 
class TestDiff(TestCase):
100
 
 
101
 
    def test_add_nl(self):
102
 
        """diff generates a valid diff for patches that add a newline"""
103
 
        lines = udiff_lines(['boo'], ['boo\n'])
104
 
        self.check_patch(lines)
105
 
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
106
 
            ## "expected no-nl, got %r" % lines[4]
107
 
 
108
 
    def test_add_nl_2(self):
109
 
        """diff generates a valid diff for patches that change last line and
110
 
        add a newline.
111
 
        """
112
 
        lines = udiff_lines(['boo'], ['goo\n'])
113
 
        self.check_patch(lines)
114
 
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
115
 
            ## "expected no-nl, got %r" % lines[4]
116
 
 
117
 
    def test_remove_nl(self):
118
 
        """diff generates a valid diff for patches that change last line and
119
 
        add a newline.
120
 
        """
121
 
        lines = udiff_lines(['boo\n'], ['boo'])
122
 
        self.check_patch(lines)
123
 
        self.assertEquals(lines[5], '\\ No newline at end of file\n')
124
 
            ## "expected no-nl, got %r" % lines[5]
125
 
 
126
 
    def check_patch(self, lines):
127
 
        self.assert_(len(lines) > 1)
128
 
            ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
129
 
        self.assert_(lines[0].startswith ('---'))
130
 
            ## 'No orig line for patch:\n%s' % "".join(lines)
131
 
        self.assert_(lines[1].startswith ('+++'))
132
 
            ## 'No mod line for patch:\n%s' % "".join(lines)
133
 
        self.assert_(len(lines) > 2)
134
 
            ## "No hunks for patch:\n%s" % "".join(lines)
135
 
        self.assert_(lines[2].startswith('@@'))
136
 
            ## "No hunk header for patch:\n%s" % "".join(lines)
137
 
        self.assert_('@@' in lines[2][2:])
138
 
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
139
 
 
140
 
    def test_binary_lines(self):
141
 
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
142
 
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
143
 
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
144
 
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
145
 
 
146
 
    def test_external_diff(self):
147
 
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
148
 
        self.check_patch(lines)
149
 
        self.assertEqual('\n', lines[-1])
150
 
 
151
 
    def test_external_diff_no_fileno(self):
152
 
        # Make sure that we can handle not having a fileno, even
153
 
        # if the diff is large
154
 
        lines = external_udiff_lines(['boo\n']*10000,
155
 
                                     ['goo\n']*10000,
156
 
                                     use_stringio=True)
157
 
        self.check_patch(lines)
158
 
 
159
 
    def test_external_diff_binary_lang_c(self):
160
 
        old_env = {}
161
 
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
162
 
            old_env[lang] = osutils.set_or_unset_env(lang, 'C')
163
 
        try:
164
 
            lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
165
 
            # Older versions of diffutils say "Binary files", newer
166
 
            # versions just say "Files".
167
 
            self.assertContainsRe(lines[0],
168
 
                                  '(Binary f|F)iles old and new differ\n')
169
 
            self.assertEquals(lines[1:], ['\n'])
170
 
        finally:
171
 
            for lang, old_val in old_env.iteritems():
172
 
                osutils.set_or_unset_env(lang, old_val)
173
 
 
174
 
    def test_no_external_diff(self):
175
 
        """Check that NoDiff is raised when diff is not available"""
176
 
        # Use os.environ['PATH'] to make sure no 'diff' command is available
177
 
        orig_path = os.environ['PATH']
178
 
        try:
179
 
            os.environ['PATH'] = ''
180
 
            self.assertRaises(NoDiff, external_diff,
181
 
                              'old', ['boo\n'], 'new', ['goo\n'],
182
 
                              StringIO(), diff_opts=['-u'])
183
 
        finally:
184
 
            os.environ['PATH'] = orig_path
185
 
        
186
 
    def test_internal_diff_default(self):
187
 
        # Default internal diff encoding is utf8
188
 
        output = StringIO()
189
 
        internal_diff(u'old_\xb5', ['old_text\n'],
190
 
                    u'new_\xe5', ['new_text\n'], output)
191
 
        lines = output.getvalue().splitlines(True)
192
 
        self.check_patch(lines)
193
 
        self.assertEquals(['--- old_\xc2\xb5\n',
194
 
                           '+++ new_\xc3\xa5\n',
195
 
                           '@@ -1,1 +1,1 @@\n',
196
 
                           '-old_text\n',
197
 
                           '+new_text\n',
198
 
                           '\n',
199
 
                          ]
200
 
                          , lines)
201
 
 
202
 
    def test_internal_diff_utf8(self):
203
 
        output = StringIO()
204
 
        internal_diff(u'old_\xb5', ['old_text\n'],
205
 
                    u'new_\xe5', ['new_text\n'], output,
206
 
                    path_encoding='utf8')
207
 
        lines = output.getvalue().splitlines(True)
208
 
        self.check_patch(lines)
209
 
        self.assertEquals(['--- old_\xc2\xb5\n',
210
 
                           '+++ new_\xc3\xa5\n',
211
 
                           '@@ -1,1 +1,1 @@\n',
212
 
                           '-old_text\n',
213
 
                           '+new_text\n',
214
 
                           '\n',
215
 
                          ]
216
 
                          , lines)
217
 
 
218
 
    def test_internal_diff_iso_8859_1(self):
219
 
        output = StringIO()
220
 
        internal_diff(u'old_\xb5', ['old_text\n'],
221
 
                    u'new_\xe5', ['new_text\n'], output,
222
 
                    path_encoding='iso-8859-1')
223
 
        lines = output.getvalue().splitlines(True)
224
 
        self.check_patch(lines)
225
 
        self.assertEquals(['--- old_\xb5\n',
226
 
                           '+++ new_\xe5\n',
227
 
                           '@@ -1,1 +1,1 @@\n',
228
 
                           '-old_text\n',
229
 
                           '+new_text\n',
230
 
                           '\n',
231
 
                          ]
232
 
                          , lines)
233
 
 
234
 
    def test_internal_diff_returns_bytes(self):
235
 
        import StringIO
236
 
        output = StringIO.StringIO()
237
 
        internal_diff(u'old_\xb5', ['old_text\n'],
238
 
                    u'new_\xe5', ['new_text\n'], output)
239
 
        self.failUnless(isinstance(output.getvalue(), str),
240
 
            'internal_diff should return bytestrings')
241
 
 
242
 
 
243
 
class TestDiffFiles(TestCaseInTempDir):
244
 
 
245
 
    def test_external_diff_binary(self):
246
 
        """The output when using external diff should use diff's i18n error"""
247
 
        # Make sure external_diff doesn't fail in the current LANG
248
 
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
249
 
 
250
 
        cmd = ['diff', '-u', '--binary', 'old', 'new']
251
 
        open('old', 'wb').write('\x00foobar\n')
252
 
        open('new', 'wb').write('foo\x00bar\n')
253
 
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
254
 
                                     stdin=subprocess.PIPE)
255
 
        out, err = pipe.communicate()
256
 
        # Diff returns '2' on Binary files.
257
 
        self.assertEqual(2, pipe.returncode)
258
 
        # We should output whatever diff tells us, plus a trailing newline
259
 
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
260
 
 
261
 
 
262
 
class TestShowDiffTreesHelper(TestCaseWithTransport):
263
 
    """Has a helper for running show_diff_trees"""
264
 
 
265
 
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
266
 
        output = StringIO()
267
 
        if working_tree is not None:
268
 
            extra_trees = (working_tree,)
269
 
        else:
270
 
            extra_trees = ()
271
 
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
272
 
                        extra_trees=extra_trees, old_label='old/',
273
 
                        new_label='new/')
274
 
        return output.getvalue()
275
 
 
276
 
 
277
 
class TestDiffDates(TestShowDiffTreesHelper):
278
 
 
279
 
    def setUp(self):
280
 
        super(TestDiffDates, self).setUp()
281
 
        self.wt = self.make_branch_and_tree('.')
282
 
        self.b = self.wt.branch
283
 
        self.build_tree_contents([
284
 
            ('file1', 'file1 contents at rev 1\n'),
285
 
            ('file2', 'file2 contents at rev 1\n')
286
 
            ])
287
 
        self.wt.add(['file1', 'file2'])
288
 
        self.wt.commit(
289
 
            message='Revision 1',
290
 
            timestamp=1143849600, # 2006-04-01 00:00:00 UTC
291
 
            timezone=0,
292
 
            rev_id='rev-1')
293
 
        self.build_tree_contents([('file1', 'file1 contents at rev 2\n')])
294
 
        self.wt.commit(
295
 
            message='Revision 2',
296
 
            timestamp=1143936000, # 2006-04-02 00:00:00 UTC
297
 
            timezone=28800,
298
 
            rev_id='rev-2')
299
 
        self.build_tree_contents([('file2', 'file2 contents at rev 3\n')])
300
 
        self.wt.commit(
301
 
            message='Revision 3',
302
 
            timestamp=1144022400, # 2006-04-03 00:00:00 UTC
303
 
            timezone=-3600,
304
 
            rev_id='rev-3')
305
 
        self.wt.remove(['file2'])
306
 
        self.wt.commit(
307
 
            message='Revision 4',
308
 
            timestamp=1144108800, # 2006-04-04 00:00:00 UTC
309
 
            timezone=0,
310
 
            rev_id='rev-4')
311
 
        self.build_tree_contents([
312
 
            ('file1', 'file1 contents in working tree\n')
313
 
            ])
314
 
        # set the date stamps for files in the working tree to known values
315
 
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
316
 
 
317
 
    def test_diff_rev_tree_working_tree(self):
318
 
        output = self.get_diff(self.wt.basis_tree(), self.wt)
319
 
        # note that the date for old/file1 is from rev 2 rather than from
320
 
        # the basis revision (rev 4)
321
 
        self.assertEqualDiff(output, '''\
322
 
=== modified file 'file1'
323
 
--- old/file1\t2006-04-02 00:00:00 +0000
324
 
+++ new/file1\t2006-04-05 00:00:00 +0000
325
 
@@ -1,1 +1,1 @@
326
 
-file1 contents at rev 2
327
 
+file1 contents in working tree
328
 
 
329
 
''')
330
 
 
331
 
    def test_diff_rev_tree_rev_tree(self):
332
 
        tree1 = self.b.repository.revision_tree('rev-2')
333
 
        tree2 = self.b.repository.revision_tree('rev-3')
334
 
        output = self.get_diff(tree1, tree2)
335
 
        self.assertEqualDiff(output, '''\
336
 
=== modified file 'file2'
337
 
--- old/file2\t2006-04-01 00:00:00 +0000
338
 
+++ new/file2\t2006-04-03 00:00:00 +0000
339
 
@@ -1,1 +1,1 @@
340
 
-file2 contents at rev 1
341
 
+file2 contents at rev 3
342
 
 
343
 
''')
344
 
        
345
 
    def test_diff_add_files(self):
346
 
        tree1 = self.b.repository.revision_tree(None)
347
 
        tree2 = self.b.repository.revision_tree('rev-1')
348
 
        output = self.get_diff(tree1, tree2)
349
 
        # the files have the epoch time stamp for the tree in which
350
 
        # they don't exist.
351
 
        self.assertEqualDiff(output, '''\
352
 
=== added file 'file1'
353
 
--- old/file1\t1970-01-01 00:00:00 +0000
354
 
+++ new/file1\t2006-04-01 00:00:00 +0000
355
 
@@ -0,0 +1,1 @@
356
 
+file1 contents at rev 1
357
 
 
358
 
=== added file 'file2'
359
 
--- old/file2\t1970-01-01 00:00:00 +0000
360
 
+++ new/file2\t2006-04-01 00:00:00 +0000
361
 
@@ -0,0 +1,1 @@
362
 
+file2 contents at rev 1
363
 
 
364
 
''')
365
 
 
366
 
    def test_diff_remove_files(self):
367
 
        tree1 = self.b.repository.revision_tree('rev-3')
368
 
        tree2 = self.b.repository.revision_tree('rev-4')
369
 
        output = self.get_diff(tree1, tree2)
370
 
        # the file has the epoch time stamp for the tree in which
371
 
        # it doesn't exist.
372
 
        self.assertEqualDiff(output, '''\
373
 
=== removed file 'file2'
374
 
--- old/file2\t2006-04-03 00:00:00 +0000
375
 
+++ new/file2\t1970-01-01 00:00:00 +0000
376
 
@@ -1,1 +0,0 @@
377
 
-file2 contents at rev 3
378
 
 
379
 
''')
380
 
 
381
 
    def test_show_diff_specified(self):
382
 
        """A working tree filename can be used to identify a file"""
383
 
        self.wt.rename_one('file1', 'file1b')
384
 
        old_tree = self.b.repository.revision_tree('rev-1')
385
 
        new_tree = self.b.repository.revision_tree('rev-4')
386
 
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'], 
387
 
                            working_tree=self.wt)
388
 
        self.assertContainsRe(out, 'file1\t')
389
 
 
390
 
    def test_recursive_diff(self):
391
 
        """Children of directories are matched"""
392
 
        os.mkdir('dir1')
393
 
        os.mkdir('dir2')
394
 
        self.wt.add(['dir1', 'dir2'])
395
 
        self.wt.rename_one('file1', 'dir1/file1')
396
 
        old_tree = self.b.repository.revision_tree('rev-1')
397
 
        new_tree = self.b.repository.revision_tree('rev-4')
398
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'], 
399
 
                            working_tree=self.wt)
400
 
        self.assertContainsRe(out, 'file1\t')
401
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'], 
402
 
                            working_tree=self.wt)
403
 
        self.assertNotContainsRe(out, 'file1\t')
404
 
 
405
 
 
406
 
 
407
 
class TestShowDiffTrees(TestShowDiffTreesHelper):
408
 
    """Direct tests for show_diff_trees"""
409
 
 
410
 
    def test_modified_file(self):
411
 
        """Test when a file is modified."""
412
 
        tree = self.make_branch_and_tree('tree')
413
 
        self.build_tree_contents([('tree/file', 'contents\n')])
414
 
        tree.add(['file'], ['file-id'])
415
 
        tree.commit('one', rev_id='rev-1')
416
 
 
417
 
        self.build_tree_contents([('tree/file', 'new contents\n')])
418
 
        diff = self.get_diff(tree.basis_tree(), tree)
419
 
        self.assertContainsRe(diff, "=== modified file 'file'\n")
420
 
        self.assertContainsRe(diff, '--- old/file\t')
421
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/file\t')
422
 
        self.assertContainsRe(diff, '-contents\n'
423
 
                                    '\\+new contents\n')
424
 
 
425
 
    def test_modified_file_in_renamed_dir(self):
426
 
        """Test when a file is modified in a renamed directory."""
427
 
        tree = self.make_branch_and_tree('tree')
428
 
        self.build_tree(['tree/dir/'])
429
 
        self.build_tree_contents([('tree/dir/file', 'contents\n')])
430
 
        tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
431
 
        tree.commit('one', rev_id='rev-1')
432
 
 
433
 
        tree.rename_one('dir', 'other')
434
 
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
435
 
        diff = self.get_diff(tree.basis_tree(), tree)
436
 
        self.assertContainsRe(diff, "=== renamed directory 'dir' => 'other'\n")
437
 
        self.assertContainsRe(diff, "=== modified file 'other/file'\n")
438
 
        # XXX: This is technically incorrect, because it used to be at another
439
 
        # location. What to do?
440
 
        self.assertContainsRe(diff, '--- old/dir/file\t')
441
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/other/file\t')
442
 
        self.assertContainsRe(diff, '-contents\n'
443
 
                                    '\\+new contents\n')
444
 
 
445
 
    def test_renamed_directory(self):
446
 
        """Test when only a directory is only renamed."""
447
 
        tree = self.make_branch_and_tree('tree')
448
 
        self.build_tree(['tree/dir/'])
449
 
        self.build_tree_contents([('tree/dir/file', 'contents\n')])
450
 
        tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
451
 
        tree.commit('one', rev_id='rev-1')
452
 
 
453
 
        tree.rename_one('dir', 'newdir')
454
 
        diff = self.get_diff(tree.basis_tree(), tree)
455
 
        # Renaming a directory should be a single "you renamed this dir" even
456
 
        # when there are files inside.
457
 
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
458
 
 
459
 
    def test_renamed_file(self):
460
 
        """Test when a file is only renamed."""
461
 
        tree = self.make_branch_and_tree('tree')
462
 
        self.build_tree_contents([('tree/file', 'contents\n')])
463
 
        tree.add(['file'], ['file-id'])
464
 
        tree.commit('one', rev_id='rev-1')
465
 
 
466
 
        tree.rename_one('file', 'newname')
467
 
        diff = self.get_diff(tree.basis_tree(), tree)
468
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
469
 
        # We shouldn't have a --- or +++ line, because there is no content
470
 
        # change
471
 
        self.assertNotContainsRe(diff, '---')
472
 
 
473
 
    def test_renamed_and_modified_file(self):
474
 
        """Test when a file is only renamed."""
475
 
        tree = self.make_branch_and_tree('tree')
476
 
        self.build_tree_contents([('tree/file', 'contents\n')])
477
 
        tree.add(['file'], ['file-id'])
478
 
        tree.commit('one', rev_id='rev-1')
479
 
 
480
 
        tree.rename_one('file', 'newname')
481
 
        self.build_tree_contents([('tree/newname', 'new contents\n')])
482
 
        diff = self.get_diff(tree.basis_tree(), tree)
483
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
484
 
        self.assertContainsRe(diff, '--- old/file\t')
485
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/newname\t')
486
 
        self.assertContainsRe(diff, '-contents\n'
487
 
                                    '\\+new contents\n')
488
 
 
489
 
    def test_binary_unicode_filenames(self):
490
 
        """Test that contents of files are *not* encoded in UTF-8 when there
491
 
        is a binary file in the diff.
492
 
        """
493
 
        # See https://bugs.launchpad.net/bugs/110092.
494
 
        self.requireFeature(UnicodeFilename)
495
 
 
496
 
        # This bug isn't triggered with cStringIO.
497
 
        from StringIO import StringIO
498
 
        tree = self.make_branch_and_tree('tree')
499
 
        alpha, omega = u'\u03b1', u'\u03c9'
500
 
        alpha_utf8, omega_utf8 = alpha.encode('utf8'), omega.encode('utf8')
501
 
        self.build_tree_contents(
502
 
            [('tree/' + alpha, chr(0)),
503
 
             ('tree/' + omega,
504
 
              ('The %s and the %s\n' % (alpha_utf8, omega_utf8)))])
505
 
        tree.add([alpha], ['file-id'])
506
 
        tree.add([omega], ['file-id-2'])
507
 
        diff_content = StringIO()
508
 
        show_diff_trees(tree.basis_tree(), tree, diff_content)
509
 
        diff = diff_content.getvalue()
510
 
        self.assertContainsRe(diff, r"=== added file '%s'" % alpha_utf8)
511
 
        self.assertContainsRe(
512
 
            diff, "Binary files a/%s.*and b/%s.* differ\n" % (alpha_utf8, alpha_utf8))
513
 
        self.assertContainsRe(diff, r"=== added file '%s'" % omega_utf8)
514
 
        self.assertContainsRe(diff, r"--- a/%s" % (omega_utf8,))
515
 
        self.assertContainsRe(diff, r"\+\+\+ b/%s" % (omega_utf8,))
516
 
 
517
 
    def test_unicode_filename(self):
518
 
        """Test when the filename are unicode."""
519
 
        self.requireFeature(UnicodeFilename)
520
 
 
521
 
        alpha, omega = u'\u03b1', u'\u03c9'
522
 
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
523
 
 
524
 
        tree = self.make_branch_and_tree('tree')
525
 
        self.build_tree_contents([('tree/ren_'+alpha, 'contents\n')])
526
 
        tree.add(['ren_'+alpha], ['file-id-2'])
527
 
        self.build_tree_contents([('tree/del_'+alpha, 'contents\n')])
528
 
        tree.add(['del_'+alpha], ['file-id-3'])
529
 
        self.build_tree_contents([('tree/mod_'+alpha, 'contents\n')])
530
 
        tree.add(['mod_'+alpha], ['file-id-4'])
531
 
 
532
 
        tree.commit('one', rev_id='rev-1')
533
 
 
534
 
        tree.rename_one('ren_'+alpha, 'ren_'+omega)
535
 
        tree.remove('del_'+alpha)
536
 
        self.build_tree_contents([('tree/add_'+alpha, 'contents\n')])
537
 
        tree.add(['add_'+alpha], ['file-id'])
538
 
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
539
 
 
540
 
        diff = self.get_diff(tree.basis_tree(), tree)
541
 
        self.assertContainsRe(diff,
542
 
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
543
 
        self.assertContainsRe(diff, "=== added file 'add_%s'"%autf8)
544
 
        self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
545
 
        self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
546
 
 
547
 
class TestPatienceDiffLib(TestCase):
548
 
 
549
 
    def setUp(self):
550
 
        super(TestPatienceDiffLib, self).setUp()
551
 
        self._unique_lcs = bzrlib._patiencediff_py.unique_lcs_py
552
 
        self._recurse_matches = bzrlib._patiencediff_py.recurse_matches_py
553
 
        self._PatienceSequenceMatcher = \
554
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
555
 
 
556
 
    def test_unique_lcs(self):
557
 
        unique_lcs = self._unique_lcs
558
 
        self.assertEquals(unique_lcs('', ''), [])
559
 
        self.assertEquals(unique_lcs('', 'a'), [])
560
 
        self.assertEquals(unique_lcs('a', ''), [])
561
 
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
562
 
        self.assertEquals(unique_lcs('a', 'b'), [])
563
 
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
564
 
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
565
 
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
566
 
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1), 
567
 
                                                         (3,3), (4,4)])
568
 
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
569
 
 
570
 
    def test_recurse_matches(self):
571
 
        def test_one(a, b, matches):
572
 
            test_matches = []
573
 
            self._recurse_matches(
574
 
                a, b, 0, 0, len(a), len(b), test_matches, 10)
575
 
            self.assertEquals(test_matches, matches)
576
 
 
577
 
        test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
578
 
                 [(0, 0), (2, 2), (4, 4)])
579
 
        test_one(['a', 'c', 'b', 'a', 'c'], ['a', 'b', 'c'],
580
 
                 [(0, 0), (2, 1), (4, 2)])
581
 
        # Even though 'bc' is not unique globally, and is surrounded by
582
 
        # non-matching lines, we should still match, because they are locally
583
 
        # unique
584
 
        test_one('abcdbce', 'afbcgdbce', [(0,0), (1, 2), (2, 3), (3, 5),
585
 
                                          (4, 6), (5, 7), (6, 8)])
586
 
 
587
 
        # recurse_matches doesn't match non-unique 
588
 
        # lines surrounded by bogus text.
589
 
        # The update has been done in patiencediff.SequenceMatcher instead
590
 
 
591
 
        # This is what it could be
592
 
        #test_one('aBccDe', 'abccde', [(0,0), (2,2), (3,3), (5,5)])
593
 
 
594
 
        # This is what it currently gives:
595
 
        test_one('aBccDe', 'abccde', [(0,0), (5,5)])
596
 
 
597
 
    def test_matching_blocks(self):
598
 
        def chk_blocks(a, b, expected_blocks):
599
 
            # difflib always adds a signature of the total
600
 
            # length, with no matching entries at the end
601
 
            s = self._PatienceSequenceMatcher(None, a, b)
602
 
            blocks = s.get_matching_blocks()
603
 
            self.assertEquals((len(a), len(b), 0), blocks[-1])
604
 
            self.assertEquals(expected_blocks, blocks[:-1])
605
 
 
606
 
        # Some basic matching tests
607
 
        chk_blocks('', '', [])
608
 
        chk_blocks([], [], [])
609
 
        chk_blocks('abc', '', [])
610
 
        chk_blocks('', 'abc', [])
611
 
        chk_blocks('abcd', 'abcd', [(0, 0, 4)])
612
 
        chk_blocks('abcd', 'abce', [(0, 0, 3)])
613
 
        chk_blocks('eabc', 'abce', [(1, 0, 3)])
614
 
        chk_blocks('eabce', 'abce', [(1, 0, 4)])
615
 
        chk_blocks('abcde', 'abXde', [(0, 0, 2), (3, 3, 2)])
616
 
        chk_blocks('abcde', 'abXYZde', [(0, 0, 2), (3, 5, 2)])
617
 
        chk_blocks('abde', 'abXYZde', [(0, 0, 2), (2, 5, 2)])
618
 
        # This may check too much, but it checks to see that 
619
 
        # a copied block stays attached to the previous section,
620
 
        # not the later one.
621
 
        # difflib would tend to grab the trailing longest match
622
 
        # which would make the diff not look right
623
 
        chk_blocks('abcdefghijklmnop', 'abcdefxydefghijklmnop',
624
 
                   [(0, 0, 6), (6, 11, 10)])
625
 
 
626
 
        # make sure it supports passing in lists
627
 
        chk_blocks(
628
 
                   ['hello there\n',
629
 
                    'world\n',
630
 
                    'how are you today?\n'],
631
 
                   ['hello there\n',
632
 
                    'how are you today?\n'],
633
 
                [(0, 0, 1), (2, 1, 1)])
634
 
 
635
 
        # non unique lines surrounded by non-matching lines
636
 
        # won't be found
637
 
        chk_blocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
638
 
 
639
 
        # But they only need to be locally unique
640
 
        chk_blocks('aBcDec', 'abcdec', [(0,0,1), (2,2,1), (4,4,2)])
641
 
 
642
 
        # non unique blocks won't be matched
643
 
        chk_blocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (8,8,1)])
644
 
 
645
 
        # but locally unique ones will
646
 
        chk_blocks('aBcdEeXcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
647
 
                                              (5,4,1), (7,5,2), (10,8,1)])
648
 
 
649
 
        chk_blocks('abbabbXd', 'cabbabxd', [(7,7,1)])
650
 
        chk_blocks('abbabbbb', 'cabbabbc', [])
651
 
        chk_blocks('bbbbbbbb', 'cbbbbbbc', [])
652
 
 
653
 
    def test_opcodes(self):
654
 
        def chk_ops(a, b, expected_codes):
655
 
            s = self._PatienceSequenceMatcher(None, a, b)
656
 
            self.assertEquals(expected_codes, s.get_opcodes())
657
 
 
658
 
        chk_ops('', '', [])
659
 
        chk_ops([], [], [])
660
 
        chk_ops('abc', '', [('delete', 0,3, 0,0)])
661
 
        chk_ops('', 'abc', [('insert', 0,0, 0,3)])
662
 
        chk_ops('abcd', 'abcd', [('equal',    0,4, 0,4)])
663
 
        chk_ops('abcd', 'abce', [('equal',   0,3, 0,3),
664
 
                                 ('replace', 3,4, 3,4)
665
 
                                ])
666
 
        chk_ops('eabc', 'abce', [('delete', 0,1, 0,0),
667
 
                                 ('equal',  1,4, 0,3),
668
 
                                 ('insert', 4,4, 3,4)
669
 
                                ])
670
 
        chk_ops('eabce', 'abce', [('delete', 0,1, 0,0),
671
 
                                  ('equal',  1,5, 0,4)
672
 
                                 ])
673
 
        chk_ops('abcde', 'abXde', [('equal',   0,2, 0,2),
674
 
                                   ('replace', 2,3, 2,3),
675
 
                                   ('equal',   3,5, 3,5)
676
 
                                  ])
677
 
        chk_ops('abcde', 'abXYZde', [('equal',   0,2, 0,2),
678
 
                                     ('replace', 2,3, 2,5),
679
 
                                     ('equal',   3,5, 5,7)
680
 
                                    ])
681
 
        chk_ops('abde', 'abXYZde', [('equal',  0,2, 0,2),
682
 
                                    ('insert', 2,2, 2,5),
683
 
                                    ('equal',  2,4, 5,7)
684
 
                                   ])
685
 
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
686
 
                [('equal',  0,6,  0,6),
687
 
                 ('insert', 6,6,  6,11),
688
 
                 ('equal',  6,16, 11,21)
689
 
                ])
690
 
        chk_ops(
691
 
                [ 'hello there\n'
692
 
                , 'world\n'
693
 
                , 'how are you today?\n'],
694
 
                [ 'hello there\n'
695
 
                , 'how are you today?\n'],
696
 
                [('equal',  0,1, 0,1),
697
 
                 ('delete', 1,2, 1,1),
698
 
                 ('equal',  2,3, 1,2),
699
 
                ])
700
 
        chk_ops('aBccDe', 'abccde', 
701
 
                [('equal',   0,1, 0,1),
702
 
                 ('replace', 1,5, 1,5),
703
 
                 ('equal',   5,6, 5,6),
704
 
                ])
705
 
        chk_ops('aBcDec', 'abcdec', 
706
 
                [('equal',   0,1, 0,1),
707
 
                 ('replace', 1,2, 1,2),
708
 
                 ('equal',   2,3, 2,3),
709
 
                 ('replace', 3,4, 3,4),
710
 
                 ('equal',   4,6, 4,6),
711
 
                ])
712
 
        chk_ops('aBcdEcdFg', 'abcdecdfg', 
713
 
                [('equal',   0,1, 0,1),
714
 
                 ('replace', 1,8, 1,8),
715
 
                 ('equal',   8,9, 8,9)
716
 
                ])
717
 
        chk_ops('aBcdEeXcdFg', 'abcdecdfg', 
718
 
                [('equal',   0,1, 0,1),
719
 
                 ('replace', 1,2, 1,2),
720
 
                 ('equal',   2,4, 2,4),
721
 
                 ('delete', 4,5, 4,4),
722
 
                 ('equal',   5,6, 4,5),
723
 
                 ('delete', 6,7, 5,5),
724
 
                 ('equal',   7,9, 5,7),
725
 
                 ('replace', 9,10, 7,8),
726
 
                 ('equal',   10,11, 8,9)
727
 
                ])
728
 
 
729
 
    def test_grouped_opcodes(self):
730
 
        def chk_ops(a, b, expected_codes, n=3):
731
 
            s = self._PatienceSequenceMatcher(None, a, b)
732
 
            self.assertEquals(expected_codes, list(s.get_grouped_opcodes(n)))
733
 
 
734
 
        chk_ops('', '', [])
735
 
        chk_ops([], [], [])
736
 
        chk_ops('abc', '', [[('delete', 0,3, 0,0)]])
737
 
        chk_ops('', 'abc', [[('insert', 0,0, 0,3)]])
738
 
        chk_ops('abcd', 'abcd', [])
739
 
        chk_ops('abcd', 'abce', [[('equal',   0,3, 0,3),
740
 
                                  ('replace', 3,4, 3,4)
741
 
                                 ]])
742
 
        chk_ops('eabc', 'abce', [[('delete', 0,1, 0,0),
743
 
                                 ('equal',  1,4, 0,3),
744
 
                                 ('insert', 4,4, 3,4)
745
 
                                ]])
746
 
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
747
 
                [[('equal',  3,6, 3,6),
748
 
                  ('insert', 6,6, 6,11),
749
 
                  ('equal',  6,9, 11,14)
750
 
                  ]])
751
 
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
752
 
                [[('equal',  2,6, 2,6),
753
 
                  ('insert', 6,6, 6,11),
754
 
                  ('equal',  6,10, 11,15)
755
 
                  ]], 4)
756
 
        chk_ops('Xabcdef', 'abcdef',
757
 
                [[('delete', 0,1, 0,0),
758
 
                  ('equal',  1,4, 0,3)
759
 
                  ]])
760
 
        chk_ops('abcdef', 'abcdefX',
761
 
                [[('equal',  3,6, 3,6),
762
 
                  ('insert', 6,6, 6,7)
763
 
                  ]])
764
 
 
765
 
 
766
 
    def test_multiple_ranges(self):
767
 
        # There was an earlier bug where we used a bad set of ranges,
768
 
        # this triggers that specific bug, to make sure it doesn't regress
769
 
        def chk_blocks(a, b, expected_blocks):
770
 
            # difflib always adds a signature of the total
771
 
            # length, with no matching entries at the end
772
 
            s = self._PatienceSequenceMatcher(None, a, b)
773
 
            blocks = s.get_matching_blocks()
774
 
            x = blocks.pop()
775
 
            self.assertEquals(x, (len(a), len(b), 0))
776
 
            self.assertEquals(expected_blocks, blocks)
777
 
 
778
 
        chk_blocks('abcdefghijklmnop'
779
 
                 , 'abcXghiYZQRSTUVWXYZijklmnop'
780
 
                 , [(0, 0, 3), (6, 4, 3), (9, 20, 7)])
781
 
 
782
 
        chk_blocks('ABCd efghIjk  L'
783
 
                 , 'AxyzBCn mo pqrstuvwI1 2  L'
784
 
                 , [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
785
 
 
786
 
        # These are rot13 code snippets.
787
 
        chk_blocks('''\
788
 
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
789
 
    """
790
 
    gnxrf_netf = ['svyr*']
791
 
    gnxrf_bcgvbaf = ['ab-erphefr']
792
 
  
793
 
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
794
 
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
795
 
        vs vf_dhvrg():
796
 
            ercbegre = nqq_ercbegre_ahyy
797
 
        ryfr:
798
 
            ercbegre = nqq_ercbegre_cevag
799
 
        fzneg_nqq(svyr_yvfg, abg ab_erphefr, ercbegre)
800
 
 
801
 
 
802
 
pynff pzq_zxqve(Pbzznaq):
803
 
'''.splitlines(True), '''\
804
 
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
805
 
 
806
 
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl 
807
 
    nqq gurz.
808
 
    """
809
 
    gnxrf_netf = ['svyr*']
810
 
    gnxrf_bcgvbaf = ['ab-erphefr', 'qel-eha']
811
 
 
812
 
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr, qel_eha=Snyfr):
813
 
        vzcbeg omeyvo.nqq
814
 
 
815
 
        vs qel_eha:
816
 
            vs vf_dhvrg():
817
 
                # Guvf vf cbvagyrff, ohg V'q engure abg envfr na reebe
818
 
                npgvba = omeyvo.nqq.nqq_npgvba_ahyy
819
 
            ryfr:
820
 
  npgvba = omeyvo.nqq.nqq_npgvba_cevag
821
 
        ryvs vf_dhvrg():
822
 
            npgvba = omeyvo.nqq.nqq_npgvba_nqq
823
 
        ryfr:
824
 
       npgvba = omeyvo.nqq.nqq_npgvba_nqq_naq_cevag
825
 
 
826
 
        omeyvo.nqq.fzneg_nqq(svyr_yvfg, abg ab_erphefr, npgvba)
827
 
 
828
 
 
829
 
pynff pzq_zxqve(Pbzznaq):
830
 
'''.splitlines(True)
831
 
, [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
832
 
 
833
 
    def test_patience_unified_diff(self):
834
 
        txt_a = ['hello there\n',
835
 
                 'world\n',
836
 
                 'how are you today?\n']
837
 
        txt_b = ['hello there\n',
838
 
                 'how are you today?\n']
839
 
        unified_diff = bzrlib.patiencediff.unified_diff
840
 
        psm = self._PatienceSequenceMatcher
841
 
        self.assertEquals([ '---  \n',
842
 
                           '+++  \n',
843
 
                           '@@ -1,3 +1,2 @@\n',
844
 
                           ' hello there\n',
845
 
                           '-world\n',
846
 
                           ' how are you today?\n'
847
 
                          ]
848
 
                          , list(unified_diff(txt_a, txt_b,
849
 
                                 sequencematcher=psm)))
850
 
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
851
 
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
852
 
        # This is the result with LongestCommonSubstring matching
853
 
        self.assertEquals(['---  \n',
854
 
                           '+++  \n',
855
 
                           '@@ -1,6 +1,11 @@\n',
856
 
                           ' a\n',
857
 
                           ' b\n',
858
 
                           ' c\n',
859
 
                           '+d\n',
860
 
                           '+e\n',
861
 
                           '+f\n',
862
 
                           '+x\n',
863
 
                           '+y\n',
864
 
                           ' d\n',
865
 
                           ' e\n',
866
 
                           ' f\n']
867
 
                          , list(unified_diff(txt_a, txt_b)))
868
 
        # And the patience diff
869
 
        self.assertEquals(['---  \n',
870
 
                           '+++  \n',
871
 
                           '@@ -4,6 +4,11 @@\n',
872
 
                           ' d\n',
873
 
                           ' e\n',
874
 
                           ' f\n',
875
 
                           '+x\n',
876
 
                           '+y\n',
877
 
                           '+d\n',
878
 
                           '+e\n',
879
 
                           '+f\n',
880
 
                           ' g\n',
881
 
                           ' h\n',
882
 
                           ' i\n',
883
 
                          ]
884
 
                          , list(unified_diff(txt_a, txt_b,
885
 
                                 sequencematcher=psm)))
886
 
 
887
 
 
888
 
class TestPatienceDiffLib_c(TestPatienceDiffLib):
889
 
 
890
 
    _test_needs_features = [CompiledPatienceDiffFeature]
891
 
 
892
 
    def setUp(self):
893
 
        super(TestPatienceDiffLib_c, self).setUp()
894
 
        import bzrlib._patiencediff_c
895
 
        self._unique_lcs = bzrlib._patiencediff_c.unique_lcs_c
896
 
        self._recurse_matches = bzrlib._patiencediff_c.recurse_matches_c
897
 
        self._PatienceSequenceMatcher = \
898
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
899
 
 
900
 
 
901
 
class TestPatienceDiffLibFiles(TestCaseInTempDir):
902
 
 
903
 
    def setUp(self):
904
 
        super(TestPatienceDiffLibFiles, self).setUp()
905
 
        self._PatienceSequenceMatcher = \
906
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
907
 
 
908
 
    def test_patience_unified_diff_files(self):
909
 
        txt_a = ['hello there\n',
910
 
                 'world\n',
911
 
                 'how are you today?\n']
912
 
        txt_b = ['hello there\n',
913
 
                 'how are you today?\n']
914
 
        open('a1', 'wb').writelines(txt_a)
915
 
        open('b1', 'wb').writelines(txt_b)
916
 
 
917
 
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
918
 
        psm = self._PatienceSequenceMatcher
919
 
        self.assertEquals(['--- a1 \n',
920
 
                           '+++ b1 \n',
921
 
                           '@@ -1,3 +1,2 @@\n',
922
 
                           ' hello there\n',
923
 
                           '-world\n',
924
 
                           ' how are you today?\n',
925
 
                          ]
926
 
                          , list(unified_diff_files('a1', 'b1',
927
 
                                 sequencematcher=psm)))
928
 
 
929
 
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
930
 
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
931
 
        open('a2', 'wb').writelines(txt_a)
932
 
        open('b2', 'wb').writelines(txt_b)
933
 
 
934
 
        # This is the result with LongestCommonSubstring matching
935
 
        self.assertEquals(['--- a2 \n',
936
 
                           '+++ b2 \n',
937
 
                           '@@ -1,6 +1,11 @@\n',
938
 
                           ' a\n',
939
 
                           ' b\n',
940
 
                           ' c\n',
941
 
                           '+d\n',
942
 
                           '+e\n',
943
 
                           '+f\n',
944
 
                           '+x\n',
945
 
                           '+y\n',
946
 
                           ' d\n',
947
 
                           ' e\n',
948
 
                           ' f\n']
949
 
                          , list(unified_diff_files('a2', 'b2')))
950
 
 
951
 
        # And the patience diff
952
 
        self.assertEquals(['--- a2 \n',
953
 
                           '+++ b2 \n',
954
 
                           '@@ -4,6 +4,11 @@\n',
955
 
                           ' d\n',
956
 
                           ' e\n',
957
 
                           ' f\n',
958
 
                           '+x\n',
959
 
                           '+y\n',
960
 
                           '+d\n',
961
 
                           '+e\n',
962
 
                           '+f\n',
963
 
                           ' g\n',
964
 
                           ' h\n',
965
 
                           ' i\n',
966
 
                          ]
967
 
                          , list(unified_diff_files('a2', 'b2',
968
 
                                 sequencematcher=psm)))
969
 
 
970
 
 
971
 
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
972
 
 
973
 
    _test_needs_features = [CompiledPatienceDiffFeature]
974
 
 
975
 
    def setUp(self):
976
 
        super(TestPatienceDiffLibFiles_c, self).setUp()
977
 
        import bzrlib._patiencediff_c
978
 
        self._PatienceSequenceMatcher = \
979
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
980
 
 
981
 
 
982
 
class TestUsingCompiledIfAvailable(TestCase):
983
 
 
984
 
    def test_PatienceSequenceMatcher(self):
985
 
        if CompiledPatienceDiffFeature.available():
986
 
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
987
 
            self.assertIs(PatienceSequenceMatcher_c,
988
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
989
 
        else:
990
 
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
991
 
            self.assertIs(PatienceSequenceMatcher_py,
992
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
993
 
 
994
 
    def test_unique_lcs(self):
995
 
        if CompiledPatienceDiffFeature.available():
996
 
            from bzrlib._patiencediff_c import unique_lcs_c
997
 
            self.assertIs(unique_lcs_c,
998
 
                          bzrlib.patiencediff.unique_lcs)
999
 
        else:
1000
 
            from bzrlib._patiencediff_py import unique_lcs_py
1001
 
            self.assertIs(unique_lcs_py,
1002
 
                          bzrlib.patiencediff.unique_lcs)
1003
 
 
1004
 
    def test_recurse_matches(self):
1005
 
        if CompiledPatienceDiffFeature.available():
1006
 
            from bzrlib._patiencediff_c import recurse_matches_c
1007
 
            self.assertIs(recurse_matches_c,
1008
 
                          bzrlib.patiencediff.recurse_matches)
1009
 
        else:
1010
 
            from bzrlib._patiencediff_py import recurse_matches_py
1011
 
            self.assertIs(recurse_matches_py,
1012
 
                          bzrlib.patiencediff.recurse_matches)