~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: 2010-09-01 08:02:42 UTC
  • mfrom: (5390.3.3 faster-revert-593560)
  • Revision ID: pqm@pqm.ubuntu.com-20100901080242-esg62ody4frwmy66
(spiv) Avoid repeatedly calling self.target.all_file_ids() in
 InterTree.iter_changes. (Andrew Bennetts)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 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
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
18
 
import os.path
19
18
from cStringIO import StringIO
20
 
import errno
21
19
import subprocess
22
20
import sys
23
 
from tempfile import TemporaryFile
 
21
import tempfile
24
22
 
25
 
from bzrlib import tests
26
 
from bzrlib.diff import (
27
 
    DiffFromTool,
28
 
    DiffPath,
29
 
    DiffSymlink,
30
 
    DiffTree,
31
 
    DiffText,
32
 
    external_diff,
33
 
    internal_diff,
34
 
    show_diff_trees,
35
 
    get_trees_and_branches_to_diff,
 
23
from bzrlib import (
 
24
    diff,
 
25
    errors,
 
26
    osutils,
 
27
    patiencediff,
 
28
    _patiencediff_py,
 
29
    revision as _mod_revision,
 
30
    revisionspec,
 
31
    revisiontree,
 
32
    tests,
 
33
    transform,
36
34
    )
37
 
from bzrlib.errors import BinaryFile, NoDiff, ExecutableMissing
38
 
import bzrlib.osutils as osutils
39
 
import bzrlib.revision as _mod_revision
40
 
import bzrlib.transform as transform
41
 
import bzrlib.patiencediff
42
 
import bzrlib._patiencediff_py
43
 
from bzrlib.tests import (Feature, TestCase, TestCaseWithTransport,
44
 
                          TestCaseInTempDir, TestSkipped)
45
 
from bzrlib.revisiontree import RevisionTree
46
 
from bzrlib.revisionspec import RevisionSpec
47
 
 
48
 
 
49
 
class _AttribFeature(Feature):
 
35
from bzrlib.symbol_versioning import deprecated_in
 
36
from bzrlib.tests import features
 
37
from bzrlib.tests.blackbox.test_diff import subst_dates
 
38
 
 
39
 
 
40
class _AttribFeature(tests.Feature):
50
41
 
51
42
    def _probe(self):
52
43
        if (sys.platform not in ('cygwin', 'win32')):
69
60
 
70
61
def udiff_lines(old, new, allow_binary=False):
71
62
    output = StringIO()
72
 
    internal_diff('old', old, 'new', new, output, allow_binary)
 
63
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
73
64
    output.seek(0, 0)
74
65
    return output.readlines()
75
66
 
79
70
        # StringIO has no fileno, so it tests a different codepath
80
71
        output = StringIO()
81
72
    else:
82
 
        output = TemporaryFile()
 
73
        output = tempfile.TemporaryFile()
83
74
    try:
84
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
85
 
    except NoDiff:
86
 
        raise TestSkipped('external "diff" not present to test')
 
75
        diff.external_diff('old', old, 'new', new, output, diff_opts=['-u'])
 
76
    except errors.NoDiff:
 
77
        raise tests.TestSkipped('external "diff" not present to test')
87
78
    output.seek(0, 0)
88
79
    lines = output.readlines()
89
80
    output.close()
90
81
    return lines
91
82
 
92
83
 
93
 
class TestDiff(TestCase):
 
84
class TestDiff(tests.TestCase):
94
85
 
95
86
    def test_add_nl(self):
96
87
        """diff generates a valid diff for patches that add a newline"""
132
123
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
133
124
 
134
125
    def test_binary_lines(self):
135
 
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
136
 
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
137
 
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
138
 
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
 
126
        empty = []
 
127
        uni_lines = [1023 * 'a' + '\x00']
 
128
        self.assertRaises(errors.BinaryFile, udiff_lines, uni_lines , empty)
 
129
        self.assertRaises(errors.BinaryFile, udiff_lines, empty, uni_lines)
 
130
        udiff_lines(uni_lines , empty, allow_binary=True)
 
131
        udiff_lines(empty, uni_lines, allow_binary=True)
139
132
 
140
133
    def test_external_diff(self):
141
134
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
171
164
        orig_path = os.environ['PATH']
172
165
        try:
173
166
            os.environ['PATH'] = ''
174
 
            self.assertRaises(NoDiff, external_diff,
 
167
            self.assertRaises(errors.NoDiff, diff.external_diff,
175
168
                              'old', ['boo\n'], 'new', ['goo\n'],
176
169
                              StringIO(), diff_opts=['-u'])
177
170
        finally:
180
173
    def test_internal_diff_default(self):
181
174
        # Default internal diff encoding is utf8
182
175
        output = StringIO()
183
 
        internal_diff(u'old_\xb5', ['old_text\n'],
184
 
                    u'new_\xe5', ['new_text\n'], output)
 
176
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
177
                           u'new_\xe5', ['new_text\n'], output)
185
178
        lines = output.getvalue().splitlines(True)
186
179
        self.check_patch(lines)
187
180
        self.assertEquals(['--- old_\xc2\xb5\n',
195
188
 
196
189
    def test_internal_diff_utf8(self):
197
190
        output = StringIO()
198
 
        internal_diff(u'old_\xb5', ['old_text\n'],
199
 
                    u'new_\xe5', ['new_text\n'], output,
200
 
                    path_encoding='utf8')
 
191
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
192
                           u'new_\xe5', ['new_text\n'], output,
 
193
                           path_encoding='utf8')
201
194
        lines = output.getvalue().splitlines(True)
202
195
        self.check_patch(lines)
203
196
        self.assertEquals(['--- old_\xc2\xb5\n',
211
204
 
212
205
    def test_internal_diff_iso_8859_1(self):
213
206
        output = StringIO()
214
 
        internal_diff(u'old_\xb5', ['old_text\n'],
215
 
                    u'new_\xe5', ['new_text\n'], output,
216
 
                    path_encoding='iso-8859-1')
 
207
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
208
                           u'new_\xe5', ['new_text\n'], output,
 
209
                           path_encoding='iso-8859-1')
217
210
        lines = output.getvalue().splitlines(True)
218
211
        self.check_patch(lines)
219
212
        self.assertEquals(['--- old_\xb5\n',
227
220
 
228
221
    def test_internal_diff_no_content(self):
229
222
        output = StringIO()
230
 
        internal_diff(u'old', [], u'new', [], output)
 
223
        diff.internal_diff(u'old', [], u'new', [], output)
231
224
        self.assertEqual('', output.getvalue())
232
225
 
233
226
    def test_internal_diff_no_changes(self):
234
227
        output = StringIO()
235
 
        internal_diff(u'old', ['text\n', 'contents\n'],
236
 
                      u'new', ['text\n', 'contents\n'],
237
 
                      output)
 
228
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
 
229
                           u'new', ['text\n', 'contents\n'],
 
230
                           output)
238
231
        self.assertEqual('', output.getvalue())
239
232
 
240
233
    def test_internal_diff_returns_bytes(self):
241
234
        import StringIO
242
235
        output = StringIO.StringIO()
243
 
        internal_diff(u'old_\xb5', ['old_text\n'],
244
 
                    u'new_\xe5', ['new_text\n'], output)
 
236
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
237
                            u'new_\xe5', ['new_text\n'], output)
245
238
        self.failUnless(isinstance(output.getvalue(), str),
246
239
            'internal_diff should return bytestrings')
247
240
 
248
241
 
249
 
class TestDiffFiles(TestCaseInTempDir):
 
242
class TestDiffFiles(tests.TestCaseInTempDir):
250
243
 
251
244
    def test_external_diff_binary(self):
252
245
        """The output when using external diff should use diff's i18n error"""
265
258
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
266
259
 
267
260
 
268
 
class TestShowDiffTreesHelper(TestCaseWithTransport):
 
261
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
269
262
    """Has a helper for running show_diff_trees"""
270
263
 
271
264
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
274
267
            extra_trees = (working_tree,)
275
268
        else:
276
269
            extra_trees = ()
277
 
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
278
 
                        extra_trees=extra_trees, old_label='old/',
279
 
                        new_label='new/')
 
270
        diff.show_diff_trees(tree1, tree2, output,
 
271
                             specific_files=specific_files,
 
272
                             extra_trees=extra_trees, old_label='old/',
 
273
                             new_label='new/')
280
274
        return output.getvalue()
281
275
 
282
276
 
421
415
        tree.commit('one', rev_id='rev-1')
422
416
 
423
417
        self.build_tree_contents([('tree/file', 'new contents\n')])
424
 
        diff = self.get_diff(tree.basis_tree(), tree)
425
 
        self.assertContainsRe(diff, "=== modified file 'file'\n")
426
 
        self.assertContainsRe(diff, '--- old/file\t')
427
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/file\t')
428
 
        self.assertContainsRe(diff, '-contents\n'
429
 
                                    '\\+new contents\n')
 
418
        d = self.get_diff(tree.basis_tree(), tree)
 
419
        self.assertContainsRe(d, "=== modified file 'file'\n")
 
420
        self.assertContainsRe(d, '--- old/file\t')
 
421
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
 
422
        self.assertContainsRe(d, '-contents\n'
 
423
                                 '\\+new contents\n')
430
424
 
431
425
    def test_modified_file_in_renamed_dir(self):
432
426
        """Test when a file is modified in a renamed directory."""
438
432
 
439
433
        tree.rename_one('dir', 'other')
440
434
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
441
 
        diff = self.get_diff(tree.basis_tree(), tree)
442
 
        self.assertContainsRe(diff, "=== renamed directory 'dir' => 'other'\n")
443
 
        self.assertContainsRe(diff, "=== modified file 'other/file'\n")
 
435
        d = self.get_diff(tree.basis_tree(), tree)
 
436
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
 
437
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
444
438
        # XXX: This is technically incorrect, because it used to be at another
445
439
        # location. What to do?
446
 
        self.assertContainsRe(diff, '--- old/dir/file\t')
447
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/other/file\t')
448
 
        self.assertContainsRe(diff, '-contents\n'
449
 
                                    '\\+new contents\n')
 
440
        self.assertContainsRe(d, '--- old/dir/file\t')
 
441
        self.assertContainsRe(d, '\\+\\+\\+ new/other/file\t')
 
442
        self.assertContainsRe(d, '-contents\n'
 
443
                                 '\\+new contents\n')
450
444
 
451
445
    def test_renamed_directory(self):
452
446
        """Test when only a directory is only renamed."""
457
451
        tree.commit('one', rev_id='rev-1')
458
452
 
459
453
        tree.rename_one('dir', 'newdir')
460
 
        diff = self.get_diff(tree.basis_tree(), tree)
 
454
        d = self.get_diff(tree.basis_tree(), tree)
461
455
        # Renaming a directory should be a single "you renamed this dir" even
462
456
        # when there are files inside.
463
 
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
 
457
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
464
458
 
465
459
    def test_renamed_file(self):
466
460
        """Test when a file is only renamed."""
470
464
        tree.commit('one', rev_id='rev-1')
471
465
 
472
466
        tree.rename_one('file', 'newname')
473
 
        diff = self.get_diff(tree.basis_tree(), tree)
474
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
 
467
        d = self.get_diff(tree.basis_tree(), tree)
 
468
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
475
469
        # We shouldn't have a --- or +++ line, because there is no content
476
470
        # change
477
 
        self.assertNotContainsRe(diff, '---')
 
471
        self.assertNotContainsRe(d, '---')
478
472
 
479
473
    def test_renamed_and_modified_file(self):
480
474
        """Test when a file is only renamed."""
485
479
 
486
480
        tree.rename_one('file', 'newname')
487
481
        self.build_tree_contents([('tree/newname', 'new contents\n')])
488
 
        diff = self.get_diff(tree.basis_tree(), tree)
489
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
490
 
        self.assertContainsRe(diff, '--- old/file\t')
491
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/newname\t')
492
 
        self.assertContainsRe(diff, '-contents\n'
493
 
                                    '\\+new contents\n')
 
482
        d = self.get_diff(tree.basis_tree(), tree)
 
483
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
 
484
        self.assertContainsRe(d, '--- old/file\t')
 
485
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
 
486
        self.assertContainsRe(d, '-contents\n'
 
487
                                 '\\+new contents\n')
494
488
 
495
489
 
496
490
    def test_internal_diff_exec_property(self):
515
509
        tree.rename_one('c', 'new-c')
516
510
        tree.rename_one('d', 'new-d')
517
511
 
518
 
        diff = self.get_diff(tree.basis_tree(), tree)
519
 
 
520
 
        self.assertContainsRe(diff, r"file 'a'.*\(properties changed:.*\+x to -x.*\)")
521
 
        self.assertContainsRe(diff, r"file 'b'.*\(properties changed:.*-x to \+x.*\)")
522
 
        self.assertContainsRe(diff, r"file 'c'.*\(properties changed:.*\+x to -x.*\)")
523
 
        self.assertContainsRe(diff, r"file 'd'.*\(properties changed:.*-x to \+x.*\)")
524
 
        self.assertNotContainsRe(diff, r"file 'e'")
525
 
        self.assertNotContainsRe(diff, r"file 'f'")
526
 
 
 
512
        d = self.get_diff(tree.basis_tree(), tree)
 
513
 
 
514
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
 
515
                                  ".*\+x to -x.*\)")
 
516
        self.assertContainsRe(d, r"file 'b'.*\(properties changed:"
 
517
                                  ".*-x to \+x.*\)")
 
518
        self.assertContainsRe(d, r"file 'c'.*\(properties changed:"
 
519
                                  ".*\+x to -x.*\)")
 
520
        self.assertContainsRe(d, r"file 'd'.*\(properties changed:"
 
521
                                  ".*-x to \+x.*\)")
 
522
        self.assertNotContainsRe(d, r"file 'e'")
 
523
        self.assertNotContainsRe(d, r"file 'f'")
527
524
 
528
525
    def test_binary_unicode_filenames(self):
529
526
        """Test that contents of files are *not* encoded in UTF-8 when there
544
541
        tree.add([alpha], ['file-id'])
545
542
        tree.add([omega], ['file-id-2'])
546
543
        diff_content = StringIO()
547
 
        show_diff_trees(tree.basis_tree(), tree, diff_content)
548
 
        diff = diff_content.getvalue()
549
 
        self.assertContainsRe(diff, r"=== added file '%s'" % alpha_utf8)
550
 
        self.assertContainsRe(
551
 
            diff, "Binary files a/%s.*and b/%s.* differ\n" % (alpha_utf8, alpha_utf8))
552
 
        self.assertContainsRe(diff, r"=== added file '%s'" % omega_utf8)
553
 
        self.assertContainsRe(diff, r"--- a/%s" % (omega_utf8,))
554
 
        self.assertContainsRe(diff, r"\+\+\+ b/%s" % (omega_utf8,))
 
544
        diff.show_diff_trees(tree.basis_tree(), tree, diff_content)
 
545
        d = diff_content.getvalue()
 
546
        self.assertContainsRe(d, r"=== added file '%s'" % alpha_utf8)
 
547
        self.assertContainsRe(d, "Binary files a/%s.*and b/%s.* differ\n"
 
548
                              % (alpha_utf8, alpha_utf8))
 
549
        self.assertContainsRe(d, r"=== added file '%s'" % omega_utf8)
 
550
        self.assertContainsRe(d, r"--- a/%s" % (omega_utf8,))
 
551
        self.assertContainsRe(d, r"\+\+\+ b/%s" % (omega_utf8,))
555
552
 
556
553
    def test_unicode_filename(self):
557
554
        """Test when the filename are unicode."""
576
573
        tree.add(['add_'+alpha], ['file-id'])
577
574
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
578
575
 
579
 
        diff = self.get_diff(tree.basis_tree(), tree)
580
 
        self.assertContainsRe(diff,
 
576
        d = self.get_diff(tree.basis_tree(), tree)
 
577
        self.assertContainsRe(d,
581
578
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
582
 
        self.assertContainsRe(diff, "=== added file 'add_%s'"%autf8)
583
 
        self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
584
 
        self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
585
 
 
586
 
 
587
 
class DiffWasIs(DiffPath):
 
579
        self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
 
580
        self.assertContainsRe(d, "=== modified file 'mod_%s'"%autf8)
 
581
        self.assertContainsRe(d, "=== removed file 'del_%s'"%autf8)
 
582
 
 
583
    def test_unicode_filename_path_encoding(self):
 
584
        """Test for bug #382699: unicode filenames on Windows should be shown
 
585
        in user encoding.
 
586
        """
 
587
        self.requireFeature(tests.UnicodeFilenameFeature)
 
588
        # The word 'test' in Russian
 
589
        _russian_test = u'\u0422\u0435\u0441\u0442'
 
590
        directory = _russian_test + u'/'
 
591
        test_txt = _russian_test + u'.txt'
 
592
        u1234 = u'\u1234.txt'
 
593
 
 
594
        tree = self.make_branch_and_tree('.')
 
595
        self.build_tree_contents([
 
596
            (test_txt, 'foo\n'),
 
597
            (u1234, 'foo\n'),
 
598
            (directory, None),
 
599
            ])
 
600
        tree.add([test_txt, u1234, directory])
 
601
 
 
602
        sio = StringIO()
 
603
        diff.show_diff_trees(tree.basis_tree(), tree, sio,
 
604
            path_encoding='cp1251')
 
605
 
 
606
        output = subst_dates(sio.getvalue())
 
607
        shouldbe = ('''\
 
608
=== added directory '%(directory)s'
 
609
=== added file '%(test_txt)s'
 
610
--- a/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
611
+++ b/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
612
@@ -0,0 +1,1 @@
 
613
+foo
 
614
 
 
615
=== added file '?.txt'
 
616
--- a/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
617
+++ b/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
618
@@ -0,0 +1,1 @@
 
619
+foo
 
620
 
 
621
''' % {'directory': _russian_test.encode('cp1251'),
 
622
       'test_txt': test_txt.encode('cp1251'),
 
623
      })
 
624
        self.assertEqualDiff(output, shouldbe)
 
625
 
 
626
 
 
627
class DiffWasIs(diff.DiffPath):
588
628
 
589
629
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
590
630
        self.to_file.write('was: ')
594
634
        pass
595
635
 
596
636
 
597
 
class TestDiffTree(TestCaseWithTransport):
 
637
class TestDiffTree(tests.TestCaseWithTransport):
598
638
 
599
639
    def setUp(self):
600
 
        TestCaseWithTransport.setUp(self)
 
640
        super(TestDiffTree, self).setUp()
601
641
        self.old_tree = self.make_branch_and_tree('old-tree')
602
642
        self.old_tree.lock_write()
603
643
        self.addCleanup(self.old_tree.unlock)
604
644
        self.new_tree = self.make_branch_and_tree('new-tree')
605
645
        self.new_tree.lock_write()
606
646
        self.addCleanup(self.new_tree.unlock)
607
 
        self.differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
647
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
608
648
 
609
649
    def test_diff_text(self):
610
650
        self.build_tree_contents([('old-tree/olddir/',),
615
655
                                  ('new-tree/newdir/newfile', 'new\n')])
616
656
        self.new_tree.add('newdir')
617
657
        self.new_tree.add('newdir/newfile', 'file-id')
618
 
        differ = DiffText(self.old_tree, self.new_tree, StringIO())
 
658
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
619
659
        differ.diff_text('file-id', None, 'old label', 'new label')
620
660
        self.assertEqual(
621
661
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
650
690
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
651
691
 
652
692
    def test_diff_symlink(self):
653
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
693
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
654
694
        differ.diff_symlink('old target', None)
655
695
        self.assertEqual("=== target was 'old target'\n",
656
696
                         differ.to_file.getvalue())
657
697
 
658
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
698
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
659
699
        differ.diff_symlink(None, 'new target')
660
700
        self.assertEqual("=== target is 'new target'\n",
661
701
                         differ.to_file.getvalue())
662
702
 
663
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
703
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
664
704
        differ.diff_symlink('old target', 'new target')
665
705
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
666
706
                         differ.to_file.getvalue())
716
756
 
717
757
    def test_register_diff(self):
718
758
        self.create_old_new()
719
 
        old_diff_factories = DiffTree.diff_factories
720
 
        DiffTree.diff_factories=old_diff_factories[:]
721
 
        DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
 
759
        old_diff_factories = diff.DiffTree.diff_factories
 
760
        diff.DiffTree.diff_factories=old_diff_factories[:]
 
761
        diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
722
762
        try:
723
 
            differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
763
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
724
764
        finally:
725
 
            DiffTree.diff_factories = old_diff_factories
 
765
            diff.DiffTree.diff_factories = old_diff_factories
726
766
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
727
767
        self.assertNotContainsRe(
728
768
            differ.to_file.getvalue(),
733
773
 
734
774
    def test_extra_factories(self):
735
775
        self.create_old_new()
736
 
        differ = DiffTree(self.old_tree, self.new_tree, StringIO(),
737
 
                            extra_factories=[DiffWasIs.from_diff_tree])
 
776
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
 
777
                               extra_factories=[DiffWasIs.from_diff_tree])
738
778
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
739
779
        self.assertNotContainsRe(
740
780
            differ.to_file.getvalue(),
753
793
            '.*a-file(.|\n)*b-file')
754
794
 
755
795
 
756
 
class TestPatienceDiffLib(TestCase):
 
796
class TestPatienceDiffLib(tests.TestCase):
757
797
 
758
798
    def setUp(self):
759
799
        super(TestPatienceDiffLib, self).setUp()
760
 
        self._unique_lcs = bzrlib._patiencediff_py.unique_lcs_py
761
 
        self._recurse_matches = bzrlib._patiencediff_py.recurse_matches_py
 
800
        self._unique_lcs = _patiencediff_py.unique_lcs_py
 
801
        self._recurse_matches = _patiencediff_py.recurse_matches_py
762
802
        self._PatienceSequenceMatcher = \
763
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
803
            _patiencediff_py.PatienceSequenceMatcher_py
764
804
 
765
805
    def test_diff_unicode_string(self):
766
806
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
1073
1113
                 'how are you today?\n']
1074
1114
        txt_b = ['hello there\n',
1075
1115
                 'how are you today?\n']
1076
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1116
        unified_diff = patiencediff.unified_diff
1077
1117
        psm = self._PatienceSequenceMatcher
1078
1118
        self.assertEquals(['--- \n',
1079
1119
                           '+++ \n',
1127
1167
                 'how are you today?\n']
1128
1168
        txt_b = ['hello there\n',
1129
1169
                 'how are you today?\n']
1130
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1170
        unified_diff = patiencediff.unified_diff
1131
1171
        psm = self._PatienceSequenceMatcher
1132
1172
        self.assertEquals(['--- a\t2008-08-08\n',
1133
1173
                           '+++ b\t2008-09-09\n',
1149
1189
 
1150
1190
    def setUp(self):
1151
1191
        super(TestPatienceDiffLib_c, self).setUp()
1152
 
        import bzrlib._patiencediff_c
1153
 
        self._unique_lcs = bzrlib._patiencediff_c.unique_lcs_c
1154
 
        self._recurse_matches = bzrlib._patiencediff_c.recurse_matches_c
 
1192
        from bzrlib import _patiencediff_c
 
1193
        self._unique_lcs = _patiencediff_c.unique_lcs_c
 
1194
        self._recurse_matches = _patiencediff_c.recurse_matches_c
1155
1195
        self._PatienceSequenceMatcher = \
1156
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
 
1196
            _patiencediff_c.PatienceSequenceMatcher_c
1157
1197
 
1158
1198
    def test_unhashable(self):
1159
1199
        """We should get a proper exception here."""
1169
1209
                                         None, ['valid'], ['valid', []])
1170
1210
 
1171
1211
 
1172
 
class TestPatienceDiffLibFiles(TestCaseInTempDir):
 
1212
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1173
1213
 
1174
1214
    def setUp(self):
1175
1215
        super(TestPatienceDiffLibFiles, self).setUp()
1176
1216
        self._PatienceSequenceMatcher = \
1177
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
1217
            _patiencediff_py.PatienceSequenceMatcher_py
1178
1218
 
1179
1219
    def test_patience_unified_diff_files(self):
1180
1220
        txt_a = ['hello there\n',
1185
1225
        open('a1', 'wb').writelines(txt_a)
1186
1226
        open('b1', 'wb').writelines(txt_b)
1187
1227
 
1188
 
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
 
1228
        unified_diff_files = patiencediff.unified_diff_files
1189
1229
        psm = self._PatienceSequenceMatcher
1190
1230
        self.assertEquals(['--- a1\n',
1191
1231
                           '+++ b1\n',
1245
1285
 
1246
1286
    def setUp(self):
1247
1287
        super(TestPatienceDiffLibFiles_c, self).setUp()
1248
 
        import bzrlib._patiencediff_c
 
1288
        from bzrlib import _patiencediff_c
1249
1289
        self._PatienceSequenceMatcher = \
1250
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
1251
 
 
1252
 
 
1253
 
class TestUsingCompiledIfAvailable(TestCase):
 
1290
            _patiencediff_c.PatienceSequenceMatcher_c
 
1291
 
 
1292
 
 
1293
class TestUsingCompiledIfAvailable(tests.TestCase):
1254
1294
 
1255
1295
    def test_PatienceSequenceMatcher(self):
1256
1296
        if compiled_patiencediff_feature.available():
1257
1297
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1258
1298
            self.assertIs(PatienceSequenceMatcher_c,
1259
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1299
                          patiencediff.PatienceSequenceMatcher)
1260
1300
        else:
1261
1301
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1262
1302
            self.assertIs(PatienceSequenceMatcher_py,
1263
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1303
                          patiencediff.PatienceSequenceMatcher)
1264
1304
 
1265
1305
    def test_unique_lcs(self):
1266
1306
        if compiled_patiencediff_feature.available():
1267
1307
            from bzrlib._patiencediff_c import unique_lcs_c
1268
1308
            self.assertIs(unique_lcs_c,
1269
 
                          bzrlib.patiencediff.unique_lcs)
 
1309
                          patiencediff.unique_lcs)
1270
1310
        else:
1271
1311
            from bzrlib._patiencediff_py import unique_lcs_py
1272
1312
            self.assertIs(unique_lcs_py,
1273
 
                          bzrlib.patiencediff.unique_lcs)
 
1313
                          patiencediff.unique_lcs)
1274
1314
 
1275
1315
    def test_recurse_matches(self):
1276
1316
        if compiled_patiencediff_feature.available():
1277
1317
            from bzrlib._patiencediff_c import recurse_matches_c
1278
1318
            self.assertIs(recurse_matches_c,
1279
 
                          bzrlib.patiencediff.recurse_matches)
 
1319
                          patiencediff.recurse_matches)
1280
1320
        else:
1281
1321
            from bzrlib._patiencediff_py import recurse_matches_py
1282
1322
            self.assertIs(recurse_matches_py,
1283
 
                          bzrlib.patiencediff.recurse_matches)
1284
 
 
1285
 
 
1286
 
class TestDiffFromTool(TestCaseWithTransport):
 
1323
                          patiencediff.recurse_matches)
 
1324
 
 
1325
 
 
1326
class TestDiffFromTool(tests.TestCaseWithTransport):
1287
1327
 
1288
1328
    def test_from_string(self):
1289
 
        diff_obj = DiffFromTool.from_string('diff', None, None, None)
 
1329
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
1290
1330
        self.addCleanup(diff_obj.finish)
1291
1331
        self.assertEqual(['diff', '@old_path', '@new_path'],
1292
1332
            diff_obj.command_template)
1293
1333
 
1294
1334
    def test_from_string_u5(self):
1295
 
        diff_obj = DiffFromTool.from_string('diff -u\\ 5', None, None, None)
 
1335
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
 
1336
                                                 None, None, None)
1296
1337
        self.addCleanup(diff_obj.finish)
1297
1338
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
1298
1339
                         diff_obj.command_template)
1299
1340
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1300
1341
                         diff_obj._get_command('old-path', 'new-path'))
1301
1342
 
 
1343
    def test_from_string_path_with_backslashes(self):
 
1344
        self.requireFeature(features.backslashdir_feature)
 
1345
        tool = 'C:\\Tools\\Diff.exe'
 
1346
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
 
1347
        self.addCleanup(diff_obj.finish)
 
1348
        self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
 
1349
                         diff_obj.command_template)
 
1350
        self.assertEqual(['C:\\Tools\\Diff.exe', 'old-path', 'new-path'],
 
1351
                         diff_obj._get_command('old-path', 'new-path'))
 
1352
 
1302
1353
    def test_execute(self):
1303
1354
        output = StringIO()
1304
 
        diff_obj = DiffFromTool(['python', '-c',
1305
 
                                 'print "@old_path @new_path"'],
1306
 
                                None, None, output)
 
1355
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1356
                                      'print "@old_path @new_path"'],
 
1357
                                     None, None, output)
1307
1358
        self.addCleanup(diff_obj.finish)
1308
1359
        diff_obj._execute('old', 'new')
1309
1360
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1310
1361
 
1311
1362
    def test_excute_missing(self):
1312
 
        diff_obj = DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1313
 
                                None, None, None)
 
1363
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
 
1364
                                     None, None, None)
1314
1365
        self.addCleanup(diff_obj.finish)
1315
 
        e = self.assertRaises(ExecutableMissing, diff_obj._execute, 'old',
1316
 
                              'new')
 
1366
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
 
1367
                              'old', 'new')
1317
1368
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1318
1369
                         ' on this machine', str(e))
1319
1370
 
1329
1380
        basis_tree = tree.basis_tree()
1330
1381
        basis_tree.lock_read()
1331
1382
        self.addCleanup(basis_tree.unlock)
1332
 
        diff_obj = DiffFromTool(['python', '-c',
1333
 
                                 'print "@old_path @new_path"'],
1334
 
                                basis_tree, tree, output)
 
1383
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1384
                                      'print "@old_path @new_path"'],
 
1385
                                     basis_tree, tree, output)
1335
1386
        diff_obj._prepare_files('file-id', 'file', 'file')
1336
1387
        # The old content should be readonly
1337
1388
        self.assertReadableByAttrib(diff_obj._root, 'old\\file',
1354
1405
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
1355
1406
        tree.add('oldname', 'file-id')
1356
1407
        tree.add('oldname2', 'file2-id')
1357
 
        tree.commit('old tree', timestamp=0)
 
1408
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
1409
        tree.commit('old tree', timestamp=315532800)
1358
1410
        tree.rename_one('oldname', 'newname')
1359
1411
        tree.rename_one('oldname2', 'newname2')
1360
1412
        self.build_tree_contents([('tree/newname', 'newcontent')])
1364
1416
        self.addCleanup(old_tree.unlock)
1365
1417
        tree.lock_read()
1366
1418
        self.addCleanup(tree.unlock)
1367
 
        diff_obj = DiffFromTool(['python', '-c',
1368
 
                                 'print "@old_path @new_path"'],
1369
 
                                old_tree, tree, output)
 
1419
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1420
                                      'print "@old_path @new_path"'],
 
1421
                                     old_tree, tree, output)
1370
1422
        self.addCleanup(diff_obj.finish)
1371
1423
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1372
1424
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1373
1425
                                                     'newname')
1374
1426
        self.assertContainsRe(old_path, 'old/oldname$')
1375
 
        self.assertEqual(0, os.stat(old_path).st_mtime)
 
1427
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
1376
1428
        self.assertContainsRe(new_path, 'tree/newname$')
1377
1429
        self.assertFileEqual('oldcontent', old_path)
1378
1430
        self.assertFileEqual('newcontent', new_path)
1382
1434
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1383
1435
 
1384
1436
 
1385
 
class TestGetTreesAndBranchesToDiff(TestCaseWithTransport):
 
1437
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
 
1438
 
 
1439
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
 
1440
        """Call get_trees_and_branches_to_diff_locked.  Overridden by
 
1441
        TestGetTreesAndBranchesToDiff.
 
1442
        """
 
1443
        return diff.get_trees_and_branches_to_diff_locked(
 
1444
            path_list, revision_specs, old_url, new_url, self.addCleanup)
1386
1445
 
1387
1446
    def test_basic(self):
1388
1447
        tree = self.make_branch_and_tree('tree')
1389
1448
        (old_tree, new_tree,
1390
1449
         old_branch, new_branch,
1391
 
         specific_files, extra_trees) = \
1392
 
            get_trees_and_branches_to_diff(['tree'], None, None, None)
 
1450
         specific_files, extra_trees) = self.call_gtabtd(
 
1451
             ['tree'], None, None, None)
1393
1452
 
1394
 
        self.assertIsInstance(old_tree, RevisionTree)
1395
 
        #print dir (old_tree)
1396
 
        self.assertEqual(_mod_revision.NULL_REVISION, old_tree.get_revision_id())
 
1453
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
 
1454
        self.assertEqual(_mod_revision.NULL_REVISION,
 
1455
                         old_tree.get_revision_id())
1397
1456
        self.assertEqual(tree.basedir, new_tree.basedir)
1398
1457
        self.assertEqual(tree.branch.base, old_branch.base)
1399
1458
        self.assertEqual(tree.branch.base, new_branch.base)
1408
1467
        self.build_tree_contents([('tree/file', 'newcontent')])
1409
1468
        tree.commit('new tree', timestamp=0, rev_id="new-id")
1410
1469
 
1411
 
        revisions = [RevisionSpec.from_string('1'),
1412
 
                     RevisionSpec.from_string('2')]
 
1470
        revisions = [revisionspec.RevisionSpec.from_string('1'),
 
1471
                     revisionspec.RevisionSpec.from_string('2')]
1413
1472
        (old_tree, new_tree,
1414
1473
         old_branch, new_branch,
1415
 
         specific_files, extra_trees) = \
1416
 
            get_trees_and_branches_to_diff(['tree'], revisions, None, None)
 
1474
         specific_files, extra_trees) = self.call_gtabtd(
 
1475
            ['tree'], revisions, None, None)
1417
1476
 
1418
 
        self.assertIsInstance(old_tree, RevisionTree)
 
1477
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1419
1478
        self.assertEqual("old-id", old_tree.get_revision_id())
1420
 
        self.assertIsInstance(new_tree, RevisionTree)
 
1479
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
1421
1480
        self.assertEqual("new-id", new_tree.get_revision_id())
1422
1481
        self.assertEqual(tree.branch.base, old_branch.base)
1423
1482
        self.assertEqual(tree.branch.base, new_branch.base)
1424
1483
        self.assertIs(None, specific_files)
1425
1484
        self.assertEqual(tree.basedir, extra_trees[0].basedir)
 
1485
 
 
1486
 
 
1487
class TestGetTreesAndBranchesToDiff(TestGetTreesAndBranchesToDiffLocked):
 
1488
    """Apply the tests for get_trees_and_branches_to_diff_locked to the
 
1489
    deprecated get_trees_and_branches_to_diff function.
 
1490
    """
 
1491
 
 
1492
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
 
1493
        return self.applyDeprecated(
 
1494
            deprecated_in((2, 2, 0)), diff.get_trees_and_branches_to_diff,
 
1495
            path_list, revision_specs, old_url, new_url)
 
1496