~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Jelmer Vernooij
  • Date: 2010-04-30 11:35:43 UTC
  • mfrom: (5195 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5197.
  • Revision ID: jelmer@samba.org-20100430113543-tiqqhmqa3d8no4iu
merge bzr.dev

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 test_win32utils
 
37
 
 
38
 
 
39
class _AttribFeature(tests.Feature):
52
40
 
53
41
    def _probe(self):
54
42
        if (sys.platform not in ('cygwin', 'win32')):
71
59
 
72
60
def udiff_lines(old, new, allow_binary=False):
73
61
    output = StringIO()
74
 
    internal_diff('old', old, 'new', new, output, allow_binary)
 
62
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
75
63
    output.seek(0, 0)
76
64
    return output.readlines()
77
65
 
81
69
        # StringIO has no fileno, so it tests a different codepath
82
70
        output = StringIO()
83
71
    else:
84
 
        output = TemporaryFile()
 
72
        output = tempfile.TemporaryFile()
85
73
    try:
86
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
87
 
    except NoDiff:
88
 
        raise TestSkipped('external "diff" not present to test')
 
74
        diff.external_diff('old', old, 'new', new, output, diff_opts=['-u'])
 
75
    except errors.NoDiff:
 
76
        raise tests.TestSkipped('external "diff" not present to test')
89
77
    output.seek(0, 0)
90
78
    lines = output.readlines()
91
79
    output.close()
92
80
    return lines
93
81
 
94
82
 
95
 
class TestDiff(TestCase):
 
83
class TestDiff(tests.TestCase):
96
84
 
97
85
    def test_add_nl(self):
98
86
        """diff generates a valid diff for patches that add a newline"""
134
122
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
135
123
 
136
124
    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)
 
125
        empty = []
 
126
        uni_lines = [1023 * 'a' + '\x00']
 
127
        self.assertRaises(errors.BinaryFile, udiff_lines, uni_lines , empty)
 
128
        self.assertRaises(errors.BinaryFile, udiff_lines, empty, uni_lines)
 
129
        udiff_lines(uni_lines , empty, allow_binary=True)
 
130
        udiff_lines(empty, uni_lines, allow_binary=True)
141
131
 
142
132
    def test_external_diff(self):
143
133
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
173
163
        orig_path = os.environ['PATH']
174
164
        try:
175
165
            os.environ['PATH'] = ''
176
 
            self.assertRaises(NoDiff, external_diff,
 
166
            self.assertRaises(errors.NoDiff, diff.external_diff,
177
167
                              'old', ['boo\n'], 'new', ['goo\n'],
178
168
                              StringIO(), diff_opts=['-u'])
179
169
        finally:
182
172
    def test_internal_diff_default(self):
183
173
        # Default internal diff encoding is utf8
184
174
        output = StringIO()
185
 
        internal_diff(u'old_\xb5', ['old_text\n'],
186
 
                    u'new_\xe5', ['new_text\n'], output)
 
175
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
176
                           u'new_\xe5', ['new_text\n'], output)
187
177
        lines = output.getvalue().splitlines(True)
188
178
        self.check_patch(lines)
189
179
        self.assertEquals(['--- old_\xc2\xb5\n',
197
187
 
198
188
    def test_internal_diff_utf8(self):
199
189
        output = StringIO()
200
 
        internal_diff(u'old_\xb5', ['old_text\n'],
201
 
                    u'new_\xe5', ['new_text\n'], output,
202
 
                    path_encoding='utf8')
 
190
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
191
                           u'new_\xe5', ['new_text\n'], output,
 
192
                           path_encoding='utf8')
203
193
        lines = output.getvalue().splitlines(True)
204
194
        self.check_patch(lines)
205
195
        self.assertEquals(['--- old_\xc2\xb5\n',
213
203
 
214
204
    def test_internal_diff_iso_8859_1(self):
215
205
        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')
 
206
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
207
                           u'new_\xe5', ['new_text\n'], output,
 
208
                           path_encoding='iso-8859-1')
219
209
        lines = output.getvalue().splitlines(True)
220
210
        self.check_patch(lines)
221
211
        self.assertEquals(['--- old_\xb5\n',
229
219
 
230
220
    def test_internal_diff_no_content(self):
231
221
        output = StringIO()
232
 
        internal_diff(u'old', [], u'new', [], output)
 
222
        diff.internal_diff(u'old', [], u'new', [], output)
233
223
        self.assertEqual('', output.getvalue())
234
224
 
235
225
    def test_internal_diff_no_changes(self):
236
226
        output = StringIO()
237
 
        internal_diff(u'old', ['text\n', 'contents\n'],
238
 
                      u'new', ['text\n', 'contents\n'],
239
 
                      output)
 
227
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
 
228
                           u'new', ['text\n', 'contents\n'],
 
229
                           output)
240
230
        self.assertEqual('', output.getvalue())
241
231
 
242
232
    def test_internal_diff_returns_bytes(self):
243
233
        import StringIO
244
234
        output = StringIO.StringIO()
245
 
        internal_diff(u'old_\xb5', ['old_text\n'],
246
 
                    u'new_\xe5', ['new_text\n'], output)
 
235
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
236
                            u'new_\xe5', ['new_text\n'], output)
247
237
        self.failUnless(isinstance(output.getvalue(), str),
248
238
            'internal_diff should return bytestrings')
249
239
 
250
240
 
251
 
class TestDiffFiles(TestCaseInTempDir):
 
241
class TestDiffFiles(tests.TestCaseInTempDir):
252
242
 
253
243
    def test_external_diff_binary(self):
254
244
        """The output when using external diff should use diff's i18n error"""
267
257
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
268
258
 
269
259
 
270
 
class TestShowDiffTreesHelper(TestCaseWithTransport):
 
260
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
271
261
    """Has a helper for running show_diff_trees"""
272
262
 
273
263
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
276
266
            extra_trees = (working_tree,)
277
267
        else:
278
268
            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/')
 
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/')
282
273
        return output.getvalue()
283
274
 
284
275
 
423
414
        tree.commit('one', rev_id='rev-1')
424
415
 
425
416
        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')
 
417
        d = self.get_diff(tree.basis_tree(), tree)
 
418
        self.assertContainsRe(d, "=== modified file 'file'\n")
 
419
        self.assertContainsRe(d, '--- old/file\t')
 
420
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
 
421
        self.assertContainsRe(d, '-contents\n'
 
422
                                 '\\+new contents\n')
432
423
 
433
424
    def test_modified_file_in_renamed_dir(self):
434
425
        """Test when a file is modified in a renamed directory."""
440
431
 
441
432
        tree.rename_one('dir', 'other')
442
433
        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")
 
434
        d = self.get_diff(tree.basis_tree(), tree)
 
435
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
 
436
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
446
437
        # XXX: This is technically incorrect, because it used to be at another
447
438
        # 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')
 
439
        self.assertContainsRe(d, '--- old/dir/file\t')
 
440
        self.assertContainsRe(d, '\\+\\+\\+ new/other/file\t')
 
441
        self.assertContainsRe(d, '-contents\n'
 
442
                                 '\\+new contents\n')
452
443
 
453
444
    def test_renamed_directory(self):
454
445
        """Test when only a directory is only renamed."""
459
450
        tree.commit('one', rev_id='rev-1')
460
451
 
461
452
        tree.rename_one('dir', 'newdir')
462
 
        diff = self.get_diff(tree.basis_tree(), tree)
 
453
        d = self.get_diff(tree.basis_tree(), tree)
463
454
        # Renaming a directory should be a single "you renamed this dir" even
464
455
        # when there are files inside.
465
 
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
 
456
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
466
457
 
467
458
    def test_renamed_file(self):
468
459
        """Test when a file is only renamed."""
472
463
        tree.commit('one', rev_id='rev-1')
473
464
 
474
465
        tree.rename_one('file', 'newname')
475
 
        diff = self.get_diff(tree.basis_tree(), tree)
476
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
 
466
        d = self.get_diff(tree.basis_tree(), tree)
 
467
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
477
468
        # We shouldn't have a --- or +++ line, because there is no content
478
469
        # change
479
 
        self.assertNotContainsRe(diff, '---')
 
470
        self.assertNotContainsRe(d, '---')
480
471
 
481
472
    def test_renamed_and_modified_file(self):
482
473
        """Test when a file is only renamed."""
487
478
 
488
479
        tree.rename_one('file', 'newname')
489
480
        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')
 
481
        d = self.get_diff(tree.basis_tree(), tree)
 
482
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
 
483
        self.assertContainsRe(d, '--- old/file\t')
 
484
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
 
485
        self.assertContainsRe(d, '-contents\n'
 
486
                                 '\\+new contents\n')
496
487
 
497
488
 
498
489
    def test_internal_diff_exec_property(self):
517
508
        tree.rename_one('c', 'new-c')
518
509
        tree.rename_one('d', 'new-d')
519
510
 
520
 
        diff = self.get_diff(tree.basis_tree(), tree)
 
511
        d = self.get_diff(tree.basis_tree(), tree)
521
512
 
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'")
 
513
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
 
514
                                  ".*\+x to -x.*\)")
 
515
        self.assertContainsRe(d, r"file 'b'.*\(properties changed:"
 
516
                                  ".*-x to \+x.*\)")
 
517
        self.assertContainsRe(d, r"file 'c'.*\(properties changed:"
 
518
                                  ".*\+x to -x.*\)")
 
519
        self.assertContainsRe(d, r"file 'd'.*\(properties changed:"
 
520
                                  ".*-x to \+x.*\)")
 
521
        self.assertNotContainsRe(d, r"file 'e'")
 
522
        self.assertNotContainsRe(d, r"file 'f'")
528
523
 
529
524
 
530
525
    def test_binary_unicode_filenames(self):
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
 
 
584
class DiffWasIs(diff.DiffPath):
590
585
 
591
586
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
592
587
        self.to_file.write('was: ')
596
591
        pass
597
592
 
598
593
 
599
 
class TestDiffTree(TestCaseWithTransport):
 
594
class TestDiffTree(tests.TestCaseWithTransport):
600
595
 
601
596
    def setUp(self):
602
 
        TestCaseWithTransport.setUp(self)
 
597
        super(TestDiffTree, self).setUp()
603
598
        self.old_tree = self.make_branch_and_tree('old-tree')
604
599
        self.old_tree.lock_write()
605
600
        self.addCleanup(self.old_tree.unlock)
606
601
        self.new_tree = self.make_branch_and_tree('new-tree')
607
602
        self.new_tree.lock_write()
608
603
        self.addCleanup(self.new_tree.unlock)
609
 
        self.differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
604
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
610
605
 
611
606
    def test_diff_text(self):
612
607
        self.build_tree_contents([('old-tree/olddir/',),
617
612
                                  ('new-tree/newdir/newfile', 'new\n')])
618
613
        self.new_tree.add('newdir')
619
614
        self.new_tree.add('newdir/newfile', 'file-id')
620
 
        differ = DiffText(self.old_tree, self.new_tree, StringIO())
 
615
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
621
616
        differ.diff_text('file-id', None, 'old label', 'new label')
622
617
        self.assertEqual(
623
618
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
652
647
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
653
648
 
654
649
    def test_diff_symlink(self):
655
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
650
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
656
651
        differ.diff_symlink('old target', None)
657
652
        self.assertEqual("=== target was 'old target'\n",
658
653
                         differ.to_file.getvalue())
659
654
 
660
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
655
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
661
656
        differ.diff_symlink(None, 'new target')
662
657
        self.assertEqual("=== target is 'new target'\n",
663
658
                         differ.to_file.getvalue())
664
659
 
665
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
660
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
666
661
        differ.diff_symlink('old target', 'new target')
667
662
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
668
663
                         differ.to_file.getvalue())
718
713
 
719
714
    def test_register_diff(self):
720
715
        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)
 
716
        old_diff_factories = diff.DiffTree.diff_factories
 
717
        diff.DiffTree.diff_factories=old_diff_factories[:]
 
718
        diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
724
719
        try:
725
 
            differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
720
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
726
721
        finally:
727
 
            DiffTree.diff_factories = old_diff_factories
 
722
            diff.DiffTree.diff_factories = old_diff_factories
728
723
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
729
724
        self.assertNotContainsRe(
730
725
            differ.to_file.getvalue(),
735
730
 
736
731
    def test_extra_factories(self):
737
732
        self.create_old_new()
738
 
        differ = DiffTree(self.old_tree, self.new_tree, StringIO(),
739
 
                            extra_factories=[DiffWasIs.from_diff_tree])
 
733
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
 
734
                               extra_factories=[DiffWasIs.from_diff_tree])
740
735
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
741
736
        self.assertNotContainsRe(
742
737
            differ.to_file.getvalue(),
755
750
            '.*a-file(.|\n)*b-file')
756
751
 
757
752
 
758
 
class TestPatienceDiffLib(TestCase):
 
753
class TestPatienceDiffLib(tests.TestCase):
759
754
 
760
755
    def setUp(self):
761
756
        super(TestPatienceDiffLib, self).setUp()
762
 
        self._unique_lcs = bzrlib._patiencediff_py.unique_lcs_py
763
 
        self._recurse_matches = bzrlib._patiencediff_py.recurse_matches_py
 
757
        self._unique_lcs = _patiencediff_py.unique_lcs_py
 
758
        self._recurse_matches = _patiencediff_py.recurse_matches_py
764
759
        self._PatienceSequenceMatcher = \
765
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
760
            _patiencediff_py.PatienceSequenceMatcher_py
766
761
 
767
762
    def test_diff_unicode_string(self):
768
763
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
1075
1070
                 'how are you today?\n']
1076
1071
        txt_b = ['hello there\n',
1077
1072
                 'how are you today?\n']
1078
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1073
        unified_diff = patiencediff.unified_diff
1079
1074
        psm = self._PatienceSequenceMatcher
1080
1075
        self.assertEquals(['--- \n',
1081
1076
                           '+++ \n',
1129
1124
                 'how are you today?\n']
1130
1125
        txt_b = ['hello there\n',
1131
1126
                 'how are you today?\n']
1132
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1127
        unified_diff = patiencediff.unified_diff
1133
1128
        psm = self._PatienceSequenceMatcher
1134
1129
        self.assertEquals(['--- a\t2008-08-08\n',
1135
1130
                           '+++ b\t2008-09-09\n',
1151
1146
 
1152
1147
    def setUp(self):
1153
1148
        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
 
1149
        from bzrlib import _patiencediff_c
 
1150
        self._unique_lcs = _patiencediff_c.unique_lcs_c
 
1151
        self._recurse_matches = _patiencediff_c.recurse_matches_c
1157
1152
        self._PatienceSequenceMatcher = \
1158
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
 
1153
            _patiencediff_c.PatienceSequenceMatcher_c
1159
1154
 
1160
1155
    def test_unhashable(self):
1161
1156
        """We should get a proper exception here."""
1171
1166
                                         None, ['valid'], ['valid', []])
1172
1167
 
1173
1168
 
1174
 
class TestPatienceDiffLibFiles(TestCaseInTempDir):
 
1169
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1175
1170
 
1176
1171
    def setUp(self):
1177
1172
        super(TestPatienceDiffLibFiles, self).setUp()
1178
1173
        self._PatienceSequenceMatcher = \
1179
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
1174
            _patiencediff_py.PatienceSequenceMatcher_py
1180
1175
 
1181
1176
    def test_patience_unified_diff_files(self):
1182
1177
        txt_a = ['hello there\n',
1187
1182
        open('a1', 'wb').writelines(txt_a)
1188
1183
        open('b1', 'wb').writelines(txt_b)
1189
1184
 
1190
 
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
 
1185
        unified_diff_files = patiencediff.unified_diff_files
1191
1186
        psm = self._PatienceSequenceMatcher
1192
1187
        self.assertEquals(['--- a1\n',
1193
1188
                           '+++ b1\n',
1247
1242
 
1248
1243
    def setUp(self):
1249
1244
        super(TestPatienceDiffLibFiles_c, self).setUp()
1250
 
        import bzrlib._patiencediff_c
 
1245
        from bzrlib import _patiencediff_c
1251
1246
        self._PatienceSequenceMatcher = \
1252
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
1253
 
 
1254
 
 
1255
 
class TestUsingCompiledIfAvailable(TestCase):
 
1247
            _patiencediff_c.PatienceSequenceMatcher_c
 
1248
 
 
1249
 
 
1250
class TestUsingCompiledIfAvailable(tests.TestCase):
1256
1251
 
1257
1252
    def test_PatienceSequenceMatcher(self):
1258
1253
        if compiled_patiencediff_feature.available():
1259
1254
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1260
1255
            self.assertIs(PatienceSequenceMatcher_c,
1261
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1256
                          patiencediff.PatienceSequenceMatcher)
1262
1257
        else:
1263
1258
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1264
1259
            self.assertIs(PatienceSequenceMatcher_py,
1265
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1260
                          patiencediff.PatienceSequenceMatcher)
1266
1261
 
1267
1262
    def test_unique_lcs(self):
1268
1263
        if compiled_patiencediff_feature.available():
1269
1264
            from bzrlib._patiencediff_c import unique_lcs_c
1270
1265
            self.assertIs(unique_lcs_c,
1271
 
                          bzrlib.patiencediff.unique_lcs)
 
1266
                          patiencediff.unique_lcs)
1272
1267
        else:
1273
1268
            from bzrlib._patiencediff_py import unique_lcs_py
1274
1269
            self.assertIs(unique_lcs_py,
1275
 
                          bzrlib.patiencediff.unique_lcs)
 
1270
                          patiencediff.unique_lcs)
1276
1271
 
1277
1272
    def test_recurse_matches(self):
1278
1273
        if compiled_patiencediff_feature.available():
1279
1274
            from bzrlib._patiencediff_c import recurse_matches_c
1280
1275
            self.assertIs(recurse_matches_c,
1281
 
                          bzrlib.patiencediff.recurse_matches)
 
1276
                          patiencediff.recurse_matches)
1282
1277
        else:
1283
1278
            from bzrlib._patiencediff_py import recurse_matches_py
1284
1279
            self.assertIs(recurse_matches_py,
1285
 
                          bzrlib.patiencediff.recurse_matches)
1286
 
 
1287
 
 
1288
 
class TestDiffFromTool(TestCaseWithTransport):
 
1280
                          patiencediff.recurse_matches)
 
1281
 
 
1282
 
 
1283
class TestDiffFromTool(tests.TestCaseWithTransport):
1289
1284
 
1290
1285
    def test_from_string(self):
1291
 
        diff_obj = DiffFromTool.from_string('diff', None, None, None)
 
1286
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
1292
1287
        self.addCleanup(diff_obj.finish)
1293
1288
        self.assertEqual(['diff', '@old_path', '@new_path'],
1294
1289
            diff_obj.command_template)
1295
1290
 
1296
1291
    def test_from_string_u5(self):
1297
 
        diff_obj = DiffFromTool.from_string('diff "-u 5"', None, None, None)
 
1292
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
 
1293
                                                 None, None, None)
1298
1294
        self.addCleanup(diff_obj.finish)
1299
1295
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
1300
1296
                         diff_obj.command_template)
1301
1297
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1302
1298
                         diff_obj._get_command('old-path', 'new-path'))
1303
 
        
 
1299
 
1304
1300
    def test_from_string_path_with_backslashes(self):
1305
 
        self.requireFeature(BackslashDirSeparatorFeature)
 
1301
        self.requireFeature(test_win32utils.BackslashDirSeparatorFeature)
1306
1302
        tool = 'C:\\Tools\\Diff.exe'
1307
 
        diff_obj = DiffFromTool.from_string(tool, None, None, None)
 
1303
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
1308
1304
        self.addCleanup(diff_obj.finish)
1309
1305
        self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
1310
1306
                         diff_obj.command_template)
1313
1309
 
1314
1310
    def test_execute(self):
1315
1311
        output = StringIO()
1316
 
        diff_obj = DiffFromTool(['python', '-c',
1317
 
                                 'print "@old_path @new_path"'],
1318
 
                                None, None, output)
 
1312
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1313
                                      'print "@old_path @new_path"'],
 
1314
                                     None, None, output)
1319
1315
        self.addCleanup(diff_obj.finish)
1320
1316
        diff_obj._execute('old', 'new')
1321
1317
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1322
1318
 
1323
1319
    def test_excute_missing(self):
1324
 
        diff_obj = DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1325
 
                                None, None, None)
 
1320
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
 
1321
                                     None, None, None)
1326
1322
        self.addCleanup(diff_obj.finish)
1327
 
        e = self.assertRaises(ExecutableMissing, diff_obj._execute, 'old',
1328
 
                              'new')
 
1323
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
 
1324
                              'old', 'new')
1329
1325
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1330
1326
                         ' on this machine', str(e))
1331
1327
 
1341
1337
        basis_tree = tree.basis_tree()
1342
1338
        basis_tree.lock_read()
1343
1339
        self.addCleanup(basis_tree.unlock)
1344
 
        diff_obj = DiffFromTool(['python', '-c',
1345
 
                                 'print "@old_path @new_path"'],
1346
 
                                basis_tree, tree, output)
 
1340
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1341
                                      'print "@old_path @new_path"'],
 
1342
                                     basis_tree, tree, output)
1347
1343
        diff_obj._prepare_files('file-id', 'file', 'file')
1348
1344
        # The old content should be readonly
1349
1345
        self.assertReadableByAttrib(diff_obj._root, 'old\\file',
1366
1362
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
1367
1363
        tree.add('oldname', 'file-id')
1368
1364
        tree.add('oldname2', 'file2-id')
1369
 
        tree.commit('old tree', timestamp=0)
 
1365
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
1366
        tree.commit('old tree', timestamp=315532800)
1370
1367
        tree.rename_one('oldname', 'newname')
1371
1368
        tree.rename_one('oldname2', 'newname2')
1372
1369
        self.build_tree_contents([('tree/newname', 'newcontent')])
1376
1373
        self.addCleanup(old_tree.unlock)
1377
1374
        tree.lock_read()
1378
1375
        self.addCleanup(tree.unlock)
1379
 
        diff_obj = DiffFromTool(['python', '-c',
1380
 
                                 'print "@old_path @new_path"'],
1381
 
                                old_tree, tree, output)
 
1376
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1377
                                      'print "@old_path @new_path"'],
 
1378
                                     old_tree, tree, output)
1382
1379
        self.addCleanup(diff_obj.finish)
1383
1380
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1384
1381
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1385
1382
                                                     'newname')
1386
1383
        self.assertContainsRe(old_path, 'old/oldname$')
1387
 
        self.assertEqual(0, os.stat(old_path).st_mtime)
 
1384
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
1388
1385
        self.assertContainsRe(new_path, 'tree/newname$')
1389
1386
        self.assertFileEqual('oldcontent', old_path)
1390
1387
        self.assertFileEqual('newcontent', new_path)
1394
1391
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1395
1392
 
1396
1393
 
1397
 
class TestGetTreesAndBranchesToDiff(TestCaseWithTransport):
 
1394
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
 
1395
 
 
1396
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
 
1397
        """Call get_trees_and_branches_to_diff_locked.  Overridden by
 
1398
        TestGetTreesAndBranchesToDiff.
 
1399
        """
 
1400
        return diff.get_trees_and_branches_to_diff_locked(
 
1401
            path_list, revision_specs, old_url, new_url, self.addCleanup)
1398
1402
 
1399
1403
    def test_basic(self):
1400
1404
        tree = self.make_branch_and_tree('tree')
1401
1405
        (old_tree, new_tree,
1402
1406
         old_branch, new_branch,
1403
 
         specific_files, extra_trees) = \
1404
 
            get_trees_and_branches_to_diff(['tree'], None, None, None)
 
1407
         specific_files, extra_trees) = self.call_gtabtd(
 
1408
             ['tree'], None, None, None)
1405
1409
 
1406
 
        self.assertIsInstance(old_tree, RevisionTree)
1407
 
        #print dir (old_tree)
1408
 
        self.assertEqual(_mod_revision.NULL_REVISION, old_tree.get_revision_id())
 
1410
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
 
1411
        self.assertEqual(_mod_revision.NULL_REVISION,
 
1412
                         old_tree.get_revision_id())
1409
1413
        self.assertEqual(tree.basedir, new_tree.basedir)
1410
1414
        self.assertEqual(tree.branch.base, old_branch.base)
1411
1415
        self.assertEqual(tree.branch.base, new_branch.base)
1420
1424
        self.build_tree_contents([('tree/file', 'newcontent')])
1421
1425
        tree.commit('new tree', timestamp=0, rev_id="new-id")
1422
1426
 
1423
 
        revisions = [RevisionSpec.from_string('1'),
1424
 
                     RevisionSpec.from_string('2')]
 
1427
        revisions = [revisionspec.RevisionSpec.from_string('1'),
 
1428
                     revisionspec.RevisionSpec.from_string('2')]
1425
1429
        (old_tree, new_tree,
1426
1430
         old_branch, new_branch,
1427
 
         specific_files, extra_trees) = \
1428
 
            get_trees_and_branches_to_diff(['tree'], revisions, None, None)
 
1431
         specific_files, extra_trees) = self.call_gtabtd(
 
1432
            ['tree'], revisions, None, None)
1429
1433
 
1430
 
        self.assertIsInstance(old_tree, RevisionTree)
 
1434
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1431
1435
        self.assertEqual("old-id", old_tree.get_revision_id())
1432
 
        self.assertIsInstance(new_tree, RevisionTree)
 
1436
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
1433
1437
        self.assertEqual("new-id", new_tree.get_revision_id())
1434
1438
        self.assertEqual(tree.branch.base, old_branch.base)
1435
1439
        self.assertEqual(tree.branch.base, new_branch.base)
1436
1440
        self.assertIs(None, specific_files)
1437
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