~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Robert Collins
  • Date: 2010-02-27 12:27:33 UTC
  • mto: This revision was merged to the branch mainline in revision 5061.
  • Revision ID: robertc@robertcollins.net-20100227122733-2o3me3fkk3pk36ns
``bzrlib.branchbuilder.BranchBuilder.build_snapshot`` now accepts a
``message_callback`` in the same way that commit does. (Robert Collins)

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