~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-29 22:03:03 UTC
  • mfrom: (5416.2.6 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20100929220303-cr95h8iwtggco721
(mbp) Add 'break-lock --force'

Show diffs side-by-side

added added

removed removed

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