~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Martin
  • Date: 2010-05-03 20:57:39 UTC
  • mto: This revision was merged to the branch mainline in revision 5204.
  • Revision ID: gzlist@googlemail.com-20100503205739-n326zdvevv0rmruh
Retain original stack and error message when translating to ValueError in bencode

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2014 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
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
17
17
import os
18
18
from cStringIO import StringIO
19
19
import subprocess
 
20
import sys
20
21
import tempfile
21
22
 
22
23
from bzrlib import (
31
32
    tests,
32
33
    transform,
33
34
    )
34
 
from bzrlib.tests import (
35
 
    features,
36
 
    EncodingAdapter,
37
 
)
38
 
from bzrlib.tests.blackbox.test_diff import subst_dates
39
 
from bzrlib.tests.scenarios import load_tests_apply_scenarios
40
 
 
41
 
 
42
 
load_tests = load_tests_apply_scenarios
 
35
from bzrlib.symbol_versioning import deprecated_in
 
36
from bzrlib.tests import test_win32utils
 
37
 
 
38
 
 
39
class _AttribFeature(tests.Feature):
 
40
 
 
41
    def _probe(self):
 
42
        if (sys.platform not in ('cygwin', 'win32')):
 
43
            return False
 
44
        try:
 
45
            proc = subprocess.Popen(['attrib', '.'], stdout=subprocess.PIPE)
 
46
        except OSError, e:
 
47
            return False
 
48
        return (0 == proc.wait())
 
49
 
 
50
    def feature_name(self):
 
51
        return 'attrib Windows command-line tool'
 
52
 
 
53
AttribFeature = _AttribFeature()
 
54
 
 
55
 
 
56
compiled_patiencediff_feature = tests.ModuleAvailableFeature(
 
57
                                    'bzrlib._patiencediff_c')
43
58
 
44
59
 
45
60
def udiff_lines(old, new, allow_binary=False):
65
80
    return lines
66
81
 
67
82
 
68
 
class TestDiffOptions(tests.TestCase):
69
 
 
70
 
    def test_unified_added(self):
71
 
        """Check for default style '-u' only if no other style specified
72
 
        in 'diff-options'.
73
 
        """
74
 
        # Verify that style defaults to unified, id est '-u' appended
75
 
        # to option list, in the absence of an alternative style.
76
 
        self.assertEqual(['-a', '-u'], diff.default_style_unified(['-a']))
77
 
 
78
 
 
79
 
class TestDiffOptionsScenarios(tests.TestCase):
80
 
 
81
 
    scenarios = [(s, dict(style=s)) for s in diff.style_option_list]
82
 
    style = None # Set by load_tests_apply_scenarios from scenarios
83
 
 
84
 
    def test_unified_not_added(self):
85
 
        # Verify that for all valid style options, '-u' is not
86
 
        # appended to option list.
87
 
        ret_opts = diff.default_style_unified(diff_opts=["%s" % (self.style,)])
88
 
        self.assertEqual(["%s" % (self.style,)], ret_opts)
89
 
 
90
 
 
91
83
class TestDiff(tests.TestCase):
92
84
 
93
85
    def test_add_nl(self):
151
143
        self.check_patch(lines)
152
144
 
153
145
    def test_external_diff_binary_lang_c(self):
 
146
        old_env = {}
154
147
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
155
 
            self.overrideEnv(lang, 'C')
156
 
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
157
 
        # Older versions of diffutils say "Binary files", newer
158
 
        # versions just say "Files".
159
 
        self.assertContainsRe(lines[0], '(Binary f|F)iles old and new differ\n')
160
 
        self.assertEquals(lines[1:], ['\n'])
 
148
            old_env[lang] = osutils.set_or_unset_env(lang, 'C')
 
149
        try:
 
150
            lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
 
151
            # Older versions of diffutils say "Binary files", newer
 
152
            # versions just say "Files".
 
153
            self.assertContainsRe(lines[0],
 
154
                                  '(Binary f|F)iles old and new differ\n')
 
155
            self.assertEquals(lines[1:], ['\n'])
 
156
        finally:
 
157
            for lang, old_val in old_env.iteritems():
 
158
                osutils.set_or_unset_env(lang, old_val)
161
159
 
162
160
    def test_no_external_diff(self):
163
161
        """Check that NoDiff is raised when diff is not available"""
164
 
        # Make sure no 'diff' command is available
165
 
        # XXX: Weird, using None instead of '' breaks the test -- vila 20101216
166
 
        self.overrideEnv('PATH', '')
167
 
        self.assertRaises(errors.NoDiff, diff.external_diff,
168
 
                          'old', ['boo\n'], 'new', ['goo\n'],
169
 
                          StringIO(), diff_opts=['-u'])
 
162
        # Use os.environ['PATH'] to make sure no 'diff' command is available
 
163
        orig_path = os.environ['PATH']
 
164
        try:
 
165
            os.environ['PATH'] = ''
 
166
            self.assertRaises(errors.NoDiff, diff.external_diff,
 
167
                              'old', ['boo\n'], 'new', ['goo\n'],
 
168
                              StringIO(), diff_opts=['-u'])
 
169
        finally:
 
170
            os.environ['PATH'] = orig_path
170
171
 
171
172
    def test_internal_diff_default(self):
172
173
        # Default internal diff encoding is utf8
233
234
        output = StringIO.StringIO()
234
235
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
235
236
                            u'new_\xe5', ['new_text\n'], output)
236
 
        self.assertIsInstance(output.getvalue(), str,
 
237
        self.failUnless(isinstance(output.getvalue(), str),
237
238
            'internal_diff should return bytestrings')
238
239
 
239
 
    def test_internal_diff_default_context(self):
240
 
        output = StringIO()
241
 
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
242
 
                           'same_text\n','same_text\n','old_text\n'],
243
 
                           'new', ['same_text\n','same_text\n','same_text\n',
244
 
                           'same_text\n','same_text\n','new_text\n'], output)
245
 
        lines = output.getvalue().splitlines(True)
246
 
        self.check_patch(lines)
247
 
        self.assertEquals(['--- old\n',
248
 
                           '+++ new\n',
249
 
                           '@@ -3,4 +3,4 @@\n',
250
 
                           ' same_text\n',
251
 
                           ' same_text\n',
252
 
                           ' same_text\n',
253
 
                           '-old_text\n',
254
 
                           '+new_text\n',
255
 
                           '\n',
256
 
                          ]
257
 
                          , lines)
258
 
 
259
 
    def test_internal_diff_no_context(self):
260
 
        output = StringIO()
261
 
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
262
 
                           'same_text\n','same_text\n','old_text\n'],
263
 
                           'new', ['same_text\n','same_text\n','same_text\n',
264
 
                           'same_text\n','same_text\n','new_text\n'], output,
265
 
                           context_lines=0)
266
 
        lines = output.getvalue().splitlines(True)
267
 
        self.check_patch(lines)
268
 
        self.assertEquals(['--- old\n',
269
 
                           '+++ new\n',
270
 
                           '@@ -6,1 +6,1 @@\n',
271
 
                           '-old_text\n',
272
 
                           '+new_text\n',
273
 
                           '\n',
274
 
                          ]
275
 
                          , lines)
276
 
 
277
 
    def test_internal_diff_more_context(self):
278
 
        output = StringIO()
279
 
        diff.internal_diff('old', ['same_text\n','same_text\n','same_text\n',
280
 
                           'same_text\n','same_text\n','old_text\n'],
281
 
                           'new', ['same_text\n','same_text\n','same_text\n',
282
 
                           'same_text\n','same_text\n','new_text\n'], output,
283
 
                           context_lines=4)
284
 
        lines = output.getvalue().splitlines(True)
285
 
        self.check_patch(lines)
286
 
        self.assertEquals(['--- old\n',
287
 
                           '+++ new\n',
288
 
                           '@@ -2,5 +2,5 @@\n',
289
 
                           ' same_text\n',
290
 
                           ' same_text\n',
291
 
                           ' same_text\n',
292
 
                           ' same_text\n',
293
 
                           '-old_text\n',
294
 
                           '+new_text\n',
295
 
                           '\n',
296
 
                          ]
297
 
                          , lines)
298
 
 
299
 
 
300
 
 
301
 
 
302
240
 
303
241
class TestDiffFiles(tests.TestCaseInTempDir):
304
242
 
308
246
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
309
247
 
310
248
        cmd = ['diff', '-u', '--binary', 'old', 'new']
311
 
        with open('old', 'wb') as f: f.write('\x00foobar\n')
312
 
        with open('new', 'wb') as f: f.write('foo\x00bar\n')
 
249
        open('old', 'wb').write('\x00foobar\n')
 
250
        open('new', 'wb').write('foo\x00bar\n')
313
251
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
314
252
                                     stdin=subprocess.PIPE)
315
253
        out, err = pipe.communicate()
319
257
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
320
258
 
321
259
 
322
 
def get_diff_as_string(tree1, tree2, specific_files=None, working_tree=None):
323
 
    output = StringIO()
324
 
    if working_tree is not None:
325
 
        extra_trees = (working_tree,)
326
 
    else:
327
 
        extra_trees = ()
328
 
    diff.show_diff_trees(tree1, tree2, output,
329
 
        specific_files=specific_files,
330
 
        extra_trees=extra_trees, old_label='old/',
331
 
        new_label='new/')
332
 
    return output.getvalue()
333
 
 
334
 
 
335
 
class TestDiffDates(tests.TestCaseWithTransport):
 
260
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
 
261
    """Has a helper for running show_diff_trees"""
 
262
 
 
263
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
 
264
        output = StringIO()
 
265
        if working_tree is not None:
 
266
            extra_trees = (working_tree,)
 
267
        else:
 
268
            extra_trees = ()
 
269
        diff.show_diff_trees(tree1, tree2, output,
 
270
                             specific_files=specific_files,
 
271
                             extra_trees=extra_trees, old_label='old/',
 
272
                             new_label='new/')
 
273
        return output.getvalue()
 
274
 
 
275
 
 
276
class TestDiffDates(TestShowDiffTreesHelper):
336
277
 
337
278
    def setUp(self):
338
279
        super(TestDiffDates, self).setUp()
373
314
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
374
315
 
375
316
    def test_diff_rev_tree_working_tree(self):
376
 
        output = get_diff_as_string(self.wt.basis_tree(), self.wt)
 
317
        output = self.get_diff(self.wt.basis_tree(), self.wt)
377
318
        # note that the date for old/file1 is from rev 2 rather than from
378
319
        # the basis revision (rev 4)
379
320
        self.assertEqualDiff(output, '''\
389
330
    def test_diff_rev_tree_rev_tree(self):
390
331
        tree1 = self.b.repository.revision_tree('rev-2')
391
332
        tree2 = self.b.repository.revision_tree('rev-3')
392
 
        output = get_diff_as_string(tree1, tree2)
 
333
        output = self.get_diff(tree1, tree2)
393
334
        self.assertEqualDiff(output, '''\
394
335
=== modified file 'file2'
395
336
--- old/file2\t2006-04-01 00:00:00 +0000
403
344
    def test_diff_add_files(self):
404
345
        tree1 = self.b.repository.revision_tree(_mod_revision.NULL_REVISION)
405
346
        tree2 = self.b.repository.revision_tree('rev-1')
406
 
        output = get_diff_as_string(tree1, tree2)
 
347
        output = self.get_diff(tree1, tree2)
407
348
        # the files have the epoch time stamp for the tree in which
408
349
        # they don't exist.
409
350
        self.assertEqualDiff(output, '''\
424
365
    def test_diff_remove_files(self):
425
366
        tree1 = self.b.repository.revision_tree('rev-3')
426
367
        tree2 = self.b.repository.revision_tree('rev-4')
427
 
        output = get_diff_as_string(tree1, tree2)
 
368
        output = self.get_diff(tree1, tree2)
428
369
        # the file has the epoch time stamp for the tree in which
429
370
        # it doesn't exist.
430
371
        self.assertEqualDiff(output, '''\
441
382
        self.wt.rename_one('file1', 'file1b')
442
383
        old_tree = self.b.repository.revision_tree('rev-1')
443
384
        new_tree = self.b.repository.revision_tree('rev-4')
444
 
        out = get_diff_as_string(old_tree, new_tree, specific_files=['file1b'],
 
385
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'],
445
386
                            working_tree=self.wt)
446
387
        self.assertContainsRe(out, 'file1\t')
447
388
 
453
394
        self.wt.rename_one('file1', 'dir1/file1')
454
395
        old_tree = self.b.repository.revision_tree('rev-1')
455
396
        new_tree = self.b.repository.revision_tree('rev-4')
456
 
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir1'],
 
397
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'],
457
398
                            working_tree=self.wt)
458
399
        self.assertContainsRe(out, 'file1\t')
459
 
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir2'],
 
400
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'],
460
401
                            working_tree=self.wt)
461
402
        self.assertNotContainsRe(out, 'file1\t')
462
403
 
463
404
 
464
 
class TestShowDiffTrees(tests.TestCaseWithTransport):
 
405
 
 
406
class TestShowDiffTrees(TestShowDiffTreesHelper):
465
407
    """Direct tests for show_diff_trees"""
466
408
 
467
409
    def test_modified_file(self):
472
414
        tree.commit('one', rev_id='rev-1')
473
415
 
474
416
        self.build_tree_contents([('tree/file', 'new contents\n')])
475
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
417
        d = self.get_diff(tree.basis_tree(), tree)
476
418
        self.assertContainsRe(d, "=== modified file 'file'\n")
477
419
        self.assertContainsRe(d, '--- old/file\t')
478
420
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
489
431
 
490
432
        tree.rename_one('dir', 'other')
491
433
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
492
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
434
        d = self.get_diff(tree.basis_tree(), tree)
493
435
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
494
436
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
495
437
        # XXX: This is technically incorrect, because it used to be at another
508
450
        tree.commit('one', rev_id='rev-1')
509
451
 
510
452
        tree.rename_one('dir', 'newdir')
511
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
453
        d = self.get_diff(tree.basis_tree(), tree)
512
454
        # Renaming a directory should be a single "you renamed this dir" even
513
455
        # when there are files inside.
514
456
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
521
463
        tree.commit('one', rev_id='rev-1')
522
464
 
523
465
        tree.rename_one('file', 'newname')
524
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
466
        d = self.get_diff(tree.basis_tree(), tree)
525
467
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
526
468
        # We shouldn't have a --- or +++ line, because there is no content
527
469
        # change
536
478
 
537
479
        tree.rename_one('file', 'newname')
538
480
        self.build_tree_contents([('tree/newname', 'new contents\n')])
539
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
481
        d = self.get_diff(tree.basis_tree(), tree)
540
482
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
541
483
        self.assertContainsRe(d, '--- old/file\t')
542
484
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
566
508
        tree.rename_one('c', 'new-c')
567
509
        tree.rename_one('d', 'new-d')
568
510
 
569
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
511
        d = self.get_diff(tree.basis_tree(), tree)
570
512
 
571
513
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
572
514
                                  ".*\+x to -x.*\)")
579
521
        self.assertNotContainsRe(d, r"file 'e'")
580
522
        self.assertNotContainsRe(d, r"file 'f'")
581
523
 
 
524
 
582
525
    def test_binary_unicode_filenames(self):
583
526
        """Test that contents of files are *not* encoded in UTF-8 when there
584
527
        is a binary file in the diff.
585
528
        """
586
529
        # See https://bugs.launchpad.net/bugs/110092.
587
 
        self.requireFeature(features.UnicodeFilenameFeature)
 
530
        self.requireFeature(tests.UnicodeFilenameFeature)
588
531
 
589
532
        # This bug isn't triggered with cStringIO.
590
533
        from StringIO import StringIO
609
552
 
610
553
    def test_unicode_filename(self):
611
554
        """Test when the filename are unicode."""
612
 
        self.requireFeature(features.UnicodeFilenameFeature)
 
555
        self.requireFeature(tests.UnicodeFilenameFeature)
613
556
 
614
557
        alpha, omega = u'\u03b1', u'\u03c9'
615
558
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
630
573
        tree.add(['add_'+alpha], ['file-id'])
631
574
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
632
575
 
633
 
        d = get_diff_as_string(tree.basis_tree(), tree)
 
576
        d = self.get_diff(tree.basis_tree(), tree)
634
577
        self.assertContainsRe(d,
635
578
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
636
579
        self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
637
580
        self.assertContainsRe(d, "=== modified file 'mod_%s'"%autf8)
638
581
        self.assertContainsRe(d, "=== removed file 'del_%s'"%autf8)
639
582
 
640
 
    def test_unicode_filename_path_encoding(self):
641
 
        """Test for bug #382699: unicode filenames on Windows should be shown
642
 
        in user encoding.
643
 
        """
644
 
        self.requireFeature(features.UnicodeFilenameFeature)
645
 
        # The word 'test' in Russian
646
 
        _russian_test = u'\u0422\u0435\u0441\u0442'
647
 
        directory = _russian_test + u'/'
648
 
        test_txt = _russian_test + u'.txt'
649
 
        u1234 = u'\u1234.txt'
650
 
 
651
 
        tree = self.make_branch_and_tree('.')
652
 
        self.build_tree_contents([
653
 
            (test_txt, 'foo\n'),
654
 
            (u1234, 'foo\n'),
655
 
            (directory, None),
656
 
            ])
657
 
        tree.add([test_txt, u1234, directory])
658
 
 
659
 
        sio = StringIO()
660
 
        diff.show_diff_trees(tree.basis_tree(), tree, sio,
661
 
            path_encoding='cp1251')
662
 
 
663
 
        output = subst_dates(sio.getvalue())
664
 
        shouldbe = ('''\
665
 
=== added directory '%(directory)s'
666
 
=== added file '%(test_txt)s'
667
 
--- a/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
668
 
+++ b/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
669
 
@@ -0,0 +1,1 @@
670
 
+foo
671
 
 
672
 
=== added file '?.txt'
673
 
--- a/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
674
 
+++ b/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
675
 
@@ -0,0 +1,1 @@
676
 
+foo
677
 
 
678
 
''' % {'directory': _russian_test.encode('cp1251'),
679
 
       'test_txt': test_txt.encode('cp1251'),
680
 
      })
681
 
        self.assertEqualDiff(output, shouldbe)
682
 
 
683
583
 
684
584
class DiffWasIs(diff.DiffPath):
685
585
 
778
678
             ' \@\@\n-old\n\+new\n\n')
779
679
 
780
680
    def test_diff_kind_change(self):
781
 
        self.requireFeature(features.SymlinkFeature)
 
681
        self.requireFeature(tests.SymlinkFeature)
782
682
        self.build_tree_contents([('old-tree/olddir/',),
783
683
                                  ('old-tree/olddir/oldfile', 'old\n')])
784
684
        self.old_tree.add('olddir')
1242
1142
 
1243
1143
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1244
1144
 
1245
 
    _test_needs_features = [features.compiled_patiencediff_feature]
 
1145
    _test_needs_features = [compiled_patiencediff_feature]
1246
1146
 
1247
1147
    def setUp(self):
1248
1148
        super(TestPatienceDiffLib_c, self).setUp()
1279
1179
                 'how are you today?\n']
1280
1180
        txt_b = ['hello there\n',
1281
1181
                 'how are you today?\n']
1282
 
        with open('a1', 'wb') as f: f.writelines(txt_a)
1283
 
        with open('b1', 'wb') as f: f.writelines(txt_b)
 
1182
        open('a1', 'wb').writelines(txt_a)
 
1183
        open('b1', 'wb').writelines(txt_b)
1284
1184
 
1285
1185
        unified_diff_files = patiencediff.unified_diff_files
1286
1186
        psm = self._PatienceSequenceMatcher
1296
1196
 
1297
1197
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1298
1198
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1299
 
        with open('a2', 'wb') as f: f.writelines(txt_a)
1300
 
        with open('b2', 'wb') as f: f.writelines(txt_b)
 
1199
        open('a2', 'wb').writelines(txt_a)
 
1200
        open('b2', 'wb').writelines(txt_b)
1301
1201
 
1302
1202
        # This is the result with LongestCommonSubstring matching
1303
1203
        self.assertEquals(['--- a2\n',
1338
1238
 
1339
1239
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1340
1240
 
1341
 
    _test_needs_features = [features.compiled_patiencediff_feature]
 
1241
    _test_needs_features = [compiled_patiencediff_feature]
1342
1242
 
1343
1243
    def setUp(self):
1344
1244
        super(TestPatienceDiffLibFiles_c, self).setUp()
1350
1250
class TestUsingCompiledIfAvailable(tests.TestCase):
1351
1251
 
1352
1252
    def test_PatienceSequenceMatcher(self):
1353
 
        if features.compiled_patiencediff_feature.available():
 
1253
        if compiled_patiencediff_feature.available():
1354
1254
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1355
1255
            self.assertIs(PatienceSequenceMatcher_c,
1356
1256
                          patiencediff.PatienceSequenceMatcher)
1360
1260
                          patiencediff.PatienceSequenceMatcher)
1361
1261
 
1362
1262
    def test_unique_lcs(self):
1363
 
        if features.compiled_patiencediff_feature.available():
 
1263
        if compiled_patiencediff_feature.available():
1364
1264
            from bzrlib._patiencediff_c import unique_lcs_c
1365
1265
            self.assertIs(unique_lcs_c,
1366
1266
                          patiencediff.unique_lcs)
1370
1270
                          patiencediff.unique_lcs)
1371
1271
 
1372
1272
    def test_recurse_matches(self):
1373
 
        if features.compiled_patiencediff_feature.available():
 
1273
        if compiled_patiencediff_feature.available():
1374
1274
            from bzrlib._patiencediff_c import recurse_matches_c
1375
1275
            self.assertIs(recurse_matches_c,
1376
1276
                          patiencediff.recurse_matches)
1398
1298
                         diff_obj._get_command('old-path', 'new-path'))
1399
1299
 
1400
1300
    def test_from_string_path_with_backslashes(self):
1401
 
        self.requireFeature(features.backslashdir_feature)
 
1301
        self.requireFeature(test_win32utils.BackslashDirSeparatorFeature)
1402
1302
        tool = 'C:\\Tools\\Diff.exe'
1403
1303
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
1404
1304
        self.addCleanup(diff_obj.finish)
1416
1316
        diff_obj._execute('old', 'new')
1417
1317
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1418
1318
 
1419
 
    def test_execute_missing(self):
 
1319
    def test_excute_missing(self):
1420
1320
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1421
1321
                                     None, None, None)
1422
1322
        self.addCleanup(diff_obj.finish)
1426
1326
                         ' on this machine', str(e))
1427
1327
 
1428
1328
    def test_prepare_files_creates_paths_readable_by_windows_tool(self):
1429
 
        self.requireFeature(features.AttribFeature)
 
1329
        self.requireFeature(AttribFeature)
1430
1330
        output = StringIO()
1431
1331
        tree = self.make_branch_and_tree('tree')
1432
1332
        self.build_tree_contents([('tree/file', 'content')])
1491
1391
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1492
1392
 
1493
1393
 
1494
 
class TestDiffFromToolEncodedFilename(tests.TestCaseWithTransport):
1495
 
 
1496
 
    def test_encodable_filename(self):
1497
 
        # Just checks file path for external diff tool.
1498
 
        # We cannot change CPython's internal encoding used by os.exec*.
1499
 
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
1500
 
                                    None, None, None)
1501
 
        for _, scenario in EncodingAdapter.encoding_scenarios:
1502
 
            encoding = scenario['encoding']
1503
 
            dirname  = scenario['info']['directory']
1504
 
            filename = scenario['info']['filename']
1505
 
 
1506
 
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1507
 
            relpath = dirname + u'/' + filename
1508
 
            fullpath = diffobj._safe_filename('safe', relpath)
1509
 
            self.assertEqual(
1510
 
                    fullpath,
1511
 
                    fullpath.encode(encoding).decode(encoding)
1512
 
                    )
1513
 
            self.assert_(fullpath.startswith(diffobj._root + '/safe'))
1514
 
 
1515
 
    def test_unencodable_filename(self):
1516
 
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
1517
 
                                    None, None, None)
1518
 
        for _, scenario in EncodingAdapter.encoding_scenarios:
1519
 
            encoding = scenario['encoding']
1520
 
            dirname  = scenario['info']['directory']
1521
 
            filename = scenario['info']['filename']
1522
 
 
1523
 
            if encoding == 'iso-8859-1':
1524
 
                encoding = 'iso-8859-2'
1525
 
            else:
1526
 
                encoding = 'iso-8859-1'
1527
 
 
1528
 
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
1529
 
            relpath = dirname + u'/' + filename
1530
 
            fullpath = diffobj._safe_filename('safe', relpath)
1531
 
            self.assertEqual(
1532
 
                    fullpath,
1533
 
                    fullpath.encode(encoding).decode(encoding)
1534
 
                    )
1535
 
            self.assert_(fullpath.startswith(diffobj._root + '/safe'))
1536
 
 
1537
 
 
1538
1394
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
1539
1395
 
1540
1396
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
1541
 
        """Call get_trees_and_branches_to_diff_locked."""
 
1397
        """Call get_trees_and_branches_to_diff_locked.  Overridden by
 
1398
        TestGetTreesAndBranchesToDiff.
 
1399
        """
1542
1400
        return diff.get_trees_and_branches_to_diff_locked(
1543
1401
            path_list, revision_specs, old_url, new_url, self.addCleanup)
1544
1402
 
1581
1439
        self.assertEqual(tree.branch.base, new_branch.base)
1582
1440
        self.assertIs(None, specific_files)
1583
1441
        self.assertEqual(tree.basedir, extra_trees[0].basedir)
 
1442
 
 
1443
 
 
1444
class TestGetTreesAndBranchesToDiff(TestGetTreesAndBranchesToDiffLocked):
 
1445
    """Apply the tests for get_trees_and_branches_to_diff_locked to the
 
1446
    deprecated get_trees_and_branches_to_diff function.
 
1447
    """
 
1448
 
 
1449
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
 
1450
        return self.applyDeprecated(
 
1451
            deprecated_in((2, 2, 0)), diff.get_trees_and_branches_to_diff,
 
1452
            path_list, revision_specs, old_url, new_url)
 
1453