/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Martin Pool
  • Date: 2010-10-08 04:38:25 UTC
  • mfrom: (5462 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5478.
  • Revision ID: mbp@sourcefrog.net-20101008043825-b181r8bo5r3qwb6j
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
18
 
import os.path
19
18
from cStringIO import StringIO
20
 
import errno
21
19
import subprocess
22
20
import sys
23
 
from tempfile import TemporaryFile
 
21
import tempfile
24
22
 
25
 
from bzrlib import tests
26
 
from bzrlib.diff import (
27
 
    DiffFromTool,
28
 
    DiffPath,
29
 
    DiffSymlink,
30
 
    DiffTree,
31
 
    DiffText,
32
 
    external_diff,
33
 
    internal_diff,
34
 
    show_diff_trees,
35
 
    get_trees_and_branches_to_diff,
 
23
from bzrlib import (
 
24
    diff,
 
25
    errors,
 
26
    osutils,
 
27
    patiencediff,
 
28
    _patiencediff_py,
 
29
    revision as _mod_revision,
 
30
    revisionspec,
 
31
    revisiontree,
 
32
    tests,
 
33
    transform,
36
34
    )
37
 
from bzrlib.errors import BinaryFile, NoDiff, ExecutableMissing
38
 
import bzrlib.osutils as osutils
39
 
import bzrlib.revision as _mod_revision
40
 
import bzrlib.transform as transform
41
 
import bzrlib.patiencediff
42
 
import bzrlib._patiencediff_py
43
 
from bzrlib.tests import (Feature, TestCase, TestCaseWithTransport,
44
 
                          TestCaseInTempDir, TestSkipped)
45
 
from bzrlib.revisiontree import RevisionTree
46
 
from bzrlib.revisionspec import RevisionSpec
47
 
 
48
 
 
49
 
class _AttribFeature(Feature):
 
35
from bzrlib.symbol_versioning import deprecated_in
 
36
from bzrlib.tests import features
 
37
from bzrlib.tests.blackbox.test_diff import subst_dates
 
38
 
 
39
 
 
40
class _AttribFeature(tests.Feature):
50
41
 
51
42
    def _probe(self):
52
43
        if (sys.platform not in ('cygwin', 'win32')):
63
54
AttribFeature = _AttribFeature()
64
55
 
65
56
 
66
 
class _CompiledPatienceDiffFeature(Feature):
67
 
 
68
 
    def _probe(self):
69
 
        try:
70
 
            import bzrlib._patiencediff_c
71
 
        except ImportError:
72
 
            return False
73
 
        return True
74
 
 
75
 
    def feature_name(self):
76
 
        return 'bzrlib._patiencediff_c'
77
 
 
78
 
CompiledPatienceDiffFeature = _CompiledPatienceDiffFeature()
 
57
compiled_patiencediff_feature = tests.ModuleAvailableFeature(
 
58
                                    'bzrlib._patiencediff_c')
79
59
 
80
60
 
81
61
def udiff_lines(old, new, allow_binary=False):
82
62
    output = StringIO()
83
 
    internal_diff('old', old, 'new', new, output, allow_binary)
 
63
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
84
64
    output.seek(0, 0)
85
65
    return output.readlines()
86
66
 
90
70
        # StringIO has no fileno, so it tests a different codepath
91
71
        output = StringIO()
92
72
    else:
93
 
        output = TemporaryFile()
 
73
        output = tempfile.TemporaryFile()
94
74
    try:
95
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
96
 
    except NoDiff:
97
 
        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')
98
78
    output.seek(0, 0)
99
79
    lines = output.readlines()
100
80
    output.close()
101
81
    return lines
102
82
 
103
83
 
104
 
class TestDiff(TestCase):
 
84
class TestDiff(tests.TestCase):
105
85
 
106
86
    def test_add_nl(self):
107
87
        """diff generates a valid diff for patches that add a newline"""
143
123
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
144
124
 
145
125
    def test_binary_lines(self):
146
 
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
147
 
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
148
 
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
149
 
        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)
150
132
 
151
133
    def test_external_diff(self):
152
134
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
182
164
        orig_path = os.environ['PATH']
183
165
        try:
184
166
            os.environ['PATH'] = ''
185
 
            self.assertRaises(NoDiff, external_diff,
 
167
            self.assertRaises(errors.NoDiff, diff.external_diff,
186
168
                              'old', ['boo\n'], 'new', ['goo\n'],
187
169
                              StringIO(), diff_opts=['-u'])
188
170
        finally:
191
173
    def test_internal_diff_default(self):
192
174
        # Default internal diff encoding is utf8
193
175
        output = StringIO()
194
 
        internal_diff(u'old_\xb5', ['old_text\n'],
195
 
                    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)
196
178
        lines = output.getvalue().splitlines(True)
197
179
        self.check_patch(lines)
198
180
        self.assertEquals(['--- old_\xc2\xb5\n',
206
188
 
207
189
    def test_internal_diff_utf8(self):
208
190
        output = StringIO()
209
 
        internal_diff(u'old_\xb5', ['old_text\n'],
210
 
                    u'new_\xe5', ['new_text\n'], output,
211
 
                    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')
212
194
        lines = output.getvalue().splitlines(True)
213
195
        self.check_patch(lines)
214
196
        self.assertEquals(['--- old_\xc2\xb5\n',
222
204
 
223
205
    def test_internal_diff_iso_8859_1(self):
224
206
        output = StringIO()
225
 
        internal_diff(u'old_\xb5', ['old_text\n'],
226
 
                    u'new_\xe5', ['new_text\n'], output,
227
 
                    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')
228
210
        lines = output.getvalue().splitlines(True)
229
211
        self.check_patch(lines)
230
212
        self.assertEquals(['--- old_\xb5\n',
238
220
 
239
221
    def test_internal_diff_no_content(self):
240
222
        output = StringIO()
241
 
        internal_diff(u'old', [], u'new', [], output)
 
223
        diff.internal_diff(u'old', [], u'new', [], output)
242
224
        self.assertEqual('', output.getvalue())
243
225
 
244
226
    def test_internal_diff_no_changes(self):
245
227
        output = StringIO()
246
 
        internal_diff(u'old', ['text\n', 'contents\n'],
247
 
                      u'new', ['text\n', 'contents\n'],
248
 
                      output)
 
228
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
 
229
                           u'new', ['text\n', 'contents\n'],
 
230
                           output)
249
231
        self.assertEqual('', output.getvalue())
250
232
 
251
233
    def test_internal_diff_returns_bytes(self):
252
234
        import StringIO
253
235
        output = StringIO.StringIO()
254
 
        internal_diff(u'old_\xb5', ['old_text\n'],
255
 
                    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)
256
238
        self.failUnless(isinstance(output.getvalue(), str),
257
239
            'internal_diff should return bytestrings')
258
240
 
259
241
 
260
 
class TestDiffFiles(TestCaseInTempDir):
 
242
class TestDiffFiles(tests.TestCaseInTempDir):
261
243
 
262
244
    def test_external_diff_binary(self):
263
245
        """The output when using external diff should use diff's i18n error"""
276
258
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
277
259
 
278
260
 
279
 
class TestShowDiffTreesHelper(TestCaseWithTransport):
 
261
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
280
262
    """Has a helper for running show_diff_trees"""
281
263
 
282
264
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
285
267
            extra_trees = (working_tree,)
286
268
        else:
287
269
            extra_trees = ()
288
 
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
289
 
                        extra_trees=extra_trees, old_label='old/',
290
 
                        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/')
291
274
        return output.getvalue()
292
275
 
293
276
 
432
415
        tree.commit('one', rev_id='rev-1')
433
416
 
434
417
        self.build_tree_contents([('tree/file', 'new contents\n')])
435
 
        diff = self.get_diff(tree.basis_tree(), tree)
436
 
        self.assertContainsRe(diff, "=== modified file 'file'\n")
437
 
        self.assertContainsRe(diff, '--- old/file\t')
438
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/file\t')
439
 
        self.assertContainsRe(diff, '-contents\n'
440
 
                                    '\\+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')
441
424
 
442
425
    def test_modified_file_in_renamed_dir(self):
443
426
        """Test when a file is modified in a renamed directory."""
449
432
 
450
433
        tree.rename_one('dir', 'other')
451
434
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
452
 
        diff = self.get_diff(tree.basis_tree(), tree)
453
 
        self.assertContainsRe(diff, "=== renamed directory 'dir' => 'other'\n")
454
 
        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")
455
438
        # XXX: This is technically incorrect, because it used to be at another
456
439
        # location. What to do?
457
 
        self.assertContainsRe(diff, '--- old/dir/file\t')
458
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/other/file\t')
459
 
        self.assertContainsRe(diff, '-contents\n'
460
 
                                    '\\+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')
461
444
 
462
445
    def test_renamed_directory(self):
463
446
        """Test when only a directory is only renamed."""
468
451
        tree.commit('one', rev_id='rev-1')
469
452
 
470
453
        tree.rename_one('dir', 'newdir')
471
 
        diff = self.get_diff(tree.basis_tree(), tree)
 
454
        d = self.get_diff(tree.basis_tree(), tree)
472
455
        # Renaming a directory should be a single "you renamed this dir" even
473
456
        # when there are files inside.
474
 
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
 
457
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
475
458
 
476
459
    def test_renamed_file(self):
477
460
        """Test when a file is only renamed."""
481
464
        tree.commit('one', rev_id='rev-1')
482
465
 
483
466
        tree.rename_one('file', 'newname')
484
 
        diff = self.get_diff(tree.basis_tree(), tree)
485
 
        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")
486
469
        # We shouldn't have a --- or +++ line, because there is no content
487
470
        # change
488
 
        self.assertNotContainsRe(diff, '---')
 
471
        self.assertNotContainsRe(d, '---')
489
472
 
490
473
    def test_renamed_and_modified_file(self):
491
474
        """Test when a file is only renamed."""
496
479
 
497
480
        tree.rename_one('file', 'newname')
498
481
        self.build_tree_contents([('tree/newname', 'new contents\n')])
499
 
        diff = self.get_diff(tree.basis_tree(), tree)
500
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
501
 
        self.assertContainsRe(diff, '--- old/file\t')
502
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/newname\t')
503
 
        self.assertContainsRe(diff, '-contents\n'
504
 
                                    '\\+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')
505
488
 
506
489
 
507
490
    def test_internal_diff_exec_property(self):
526
509
        tree.rename_one('c', 'new-c')
527
510
        tree.rename_one('d', 'new-d')
528
511
 
529
 
        diff = self.get_diff(tree.basis_tree(), tree)
530
 
 
531
 
        self.assertContainsRe(diff, r"file 'a'.*\(properties changed:.*\+x to -x.*\)")
532
 
        self.assertContainsRe(diff, r"file 'b'.*\(properties changed:.*-x to \+x.*\)")
533
 
        self.assertContainsRe(diff, r"file 'c'.*\(properties changed:.*\+x to -x.*\)")
534
 
        self.assertContainsRe(diff, r"file 'd'.*\(properties changed:.*-x to \+x.*\)")
535
 
        self.assertNotContainsRe(diff, r"file 'e'")
536
 
        self.assertNotContainsRe(diff, r"file 'f'")
537
 
 
 
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'")
538
524
 
539
525
    def test_binary_unicode_filenames(self):
540
526
        """Test that contents of files are *not* encoded in UTF-8 when there
555
541
        tree.add([alpha], ['file-id'])
556
542
        tree.add([omega], ['file-id-2'])
557
543
        diff_content = StringIO()
558
 
        show_diff_trees(tree.basis_tree(), tree, diff_content)
559
 
        diff = diff_content.getvalue()
560
 
        self.assertContainsRe(diff, r"=== added file '%s'" % alpha_utf8)
561
 
        self.assertContainsRe(
562
 
            diff, "Binary files a/%s.*and b/%s.* differ\n" % (alpha_utf8, alpha_utf8))
563
 
        self.assertContainsRe(diff, r"=== added file '%s'" % omega_utf8)
564
 
        self.assertContainsRe(diff, r"--- a/%s" % (omega_utf8,))
565
 
        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,))
566
552
 
567
553
    def test_unicode_filename(self):
568
554
        """Test when the filename are unicode."""
587
573
        tree.add(['add_'+alpha], ['file-id'])
588
574
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
589
575
 
590
 
        diff = self.get_diff(tree.basis_tree(), tree)
591
 
        self.assertContainsRe(diff,
 
576
        d = self.get_diff(tree.basis_tree(), tree)
 
577
        self.assertContainsRe(d,
592
578
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
593
 
        self.assertContainsRe(diff, "=== added file 'add_%s'"%autf8)
594
 
        self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
595
 
        self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
596
 
 
597
 
 
598
 
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):
599
628
 
600
629
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
601
630
        self.to_file.write('was: ')
605
634
        pass
606
635
 
607
636
 
608
 
class TestDiffTree(TestCaseWithTransport):
 
637
class TestDiffTree(tests.TestCaseWithTransport):
609
638
 
610
639
    def setUp(self):
611
 
        TestCaseWithTransport.setUp(self)
 
640
        super(TestDiffTree, self).setUp()
612
641
        self.old_tree = self.make_branch_and_tree('old-tree')
613
642
        self.old_tree.lock_write()
614
643
        self.addCleanup(self.old_tree.unlock)
615
644
        self.new_tree = self.make_branch_and_tree('new-tree')
616
645
        self.new_tree.lock_write()
617
646
        self.addCleanup(self.new_tree.unlock)
618
 
        self.differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
647
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
619
648
 
620
649
    def test_diff_text(self):
621
650
        self.build_tree_contents([('old-tree/olddir/',),
626
655
                                  ('new-tree/newdir/newfile', 'new\n')])
627
656
        self.new_tree.add('newdir')
628
657
        self.new_tree.add('newdir/newfile', 'file-id')
629
 
        differ = DiffText(self.old_tree, self.new_tree, StringIO())
 
658
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
630
659
        differ.diff_text('file-id', None, 'old label', 'new label')
631
660
        self.assertEqual(
632
661
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
661
690
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
662
691
 
663
692
    def test_diff_symlink(self):
664
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
693
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
665
694
        differ.diff_symlink('old target', None)
666
695
        self.assertEqual("=== target was 'old target'\n",
667
696
                         differ.to_file.getvalue())
668
697
 
669
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
698
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
670
699
        differ.diff_symlink(None, 'new target')
671
700
        self.assertEqual("=== target is 'new target'\n",
672
701
                         differ.to_file.getvalue())
673
702
 
674
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
703
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
675
704
        differ.diff_symlink('old target', 'new target')
676
705
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
677
706
                         differ.to_file.getvalue())
727
756
 
728
757
    def test_register_diff(self):
729
758
        self.create_old_new()
730
 
        old_diff_factories = DiffTree.diff_factories
731
 
        DiffTree.diff_factories=old_diff_factories[:]
732
 
        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)
733
762
        try:
734
 
            differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
763
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
735
764
        finally:
736
 
            DiffTree.diff_factories = old_diff_factories
 
765
            diff.DiffTree.diff_factories = old_diff_factories
737
766
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
738
767
        self.assertNotContainsRe(
739
768
            differ.to_file.getvalue(),
744
773
 
745
774
    def test_extra_factories(self):
746
775
        self.create_old_new()
747
 
        differ = DiffTree(self.old_tree, self.new_tree, StringIO(),
748
 
                            extra_factories=[DiffWasIs.from_diff_tree])
 
776
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
 
777
                               extra_factories=[DiffWasIs.from_diff_tree])
749
778
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
750
779
        self.assertNotContainsRe(
751
780
            differ.to_file.getvalue(),
764
793
            '.*a-file(.|\n)*b-file')
765
794
 
766
795
 
767
 
class TestPatienceDiffLib(TestCase):
 
796
class TestPatienceDiffLib(tests.TestCase):
768
797
 
769
798
    def setUp(self):
770
799
        super(TestPatienceDiffLib, self).setUp()
771
 
        self._unique_lcs = bzrlib._patiencediff_py.unique_lcs_py
772
 
        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
773
802
        self._PatienceSequenceMatcher = \
774
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
803
            _patiencediff_py.PatienceSequenceMatcher_py
775
804
 
776
805
    def test_diff_unicode_string(self):
777
806
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
1084
1113
                 'how are you today?\n']
1085
1114
        txt_b = ['hello there\n',
1086
1115
                 'how are you today?\n']
1087
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1116
        unified_diff = patiencediff.unified_diff
1088
1117
        psm = self._PatienceSequenceMatcher
1089
1118
        self.assertEquals(['--- \n',
1090
1119
                           '+++ \n',
1138
1167
                 'how are you today?\n']
1139
1168
        txt_b = ['hello there\n',
1140
1169
                 'how are you today?\n']
1141
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1170
        unified_diff = patiencediff.unified_diff
1142
1171
        psm = self._PatienceSequenceMatcher
1143
1172
        self.assertEquals(['--- a\t2008-08-08\n',
1144
1173
                           '+++ b\t2008-09-09\n',
1156
1185
 
1157
1186
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1158
1187
 
1159
 
    _test_needs_features = [CompiledPatienceDiffFeature]
 
1188
    _test_needs_features = [compiled_patiencediff_feature]
1160
1189
 
1161
1190
    def setUp(self):
1162
1191
        super(TestPatienceDiffLib_c, self).setUp()
1163
 
        import bzrlib._patiencediff_c
1164
 
        self._unique_lcs = bzrlib._patiencediff_c.unique_lcs_c
1165
 
        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
1166
1195
        self._PatienceSequenceMatcher = \
1167
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
 
1196
            _patiencediff_c.PatienceSequenceMatcher_c
1168
1197
 
1169
1198
    def test_unhashable(self):
1170
1199
        """We should get a proper exception here."""
1180
1209
                                         None, ['valid'], ['valid', []])
1181
1210
 
1182
1211
 
1183
 
class TestPatienceDiffLibFiles(TestCaseInTempDir):
 
1212
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1184
1213
 
1185
1214
    def setUp(self):
1186
1215
        super(TestPatienceDiffLibFiles, self).setUp()
1187
1216
        self._PatienceSequenceMatcher = \
1188
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
1217
            _patiencediff_py.PatienceSequenceMatcher_py
1189
1218
 
1190
1219
    def test_patience_unified_diff_files(self):
1191
1220
        txt_a = ['hello there\n',
1196
1225
        open('a1', 'wb').writelines(txt_a)
1197
1226
        open('b1', 'wb').writelines(txt_b)
1198
1227
 
1199
 
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
 
1228
        unified_diff_files = patiencediff.unified_diff_files
1200
1229
        psm = self._PatienceSequenceMatcher
1201
1230
        self.assertEquals(['--- a1\n',
1202
1231
                           '+++ b1\n',
1252
1281
 
1253
1282
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1254
1283
 
1255
 
    _test_needs_features = [CompiledPatienceDiffFeature]
 
1284
    _test_needs_features = [compiled_patiencediff_feature]
1256
1285
 
1257
1286
    def setUp(self):
1258
1287
        super(TestPatienceDiffLibFiles_c, self).setUp()
1259
 
        import bzrlib._patiencediff_c
 
1288
        from bzrlib import _patiencediff_c
1260
1289
        self._PatienceSequenceMatcher = \
1261
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
1262
 
 
1263
 
 
1264
 
class TestUsingCompiledIfAvailable(TestCase):
 
1290
            _patiencediff_c.PatienceSequenceMatcher_c
 
1291
 
 
1292
 
 
1293
class TestUsingCompiledIfAvailable(tests.TestCase):
1265
1294
 
1266
1295
    def test_PatienceSequenceMatcher(self):
1267
 
        if CompiledPatienceDiffFeature.available():
 
1296
        if compiled_patiencediff_feature.available():
1268
1297
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1269
1298
            self.assertIs(PatienceSequenceMatcher_c,
1270
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1299
                          patiencediff.PatienceSequenceMatcher)
1271
1300
        else:
1272
1301
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1273
1302
            self.assertIs(PatienceSequenceMatcher_py,
1274
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1303
                          patiencediff.PatienceSequenceMatcher)
1275
1304
 
1276
1305
    def test_unique_lcs(self):
1277
 
        if CompiledPatienceDiffFeature.available():
 
1306
        if compiled_patiencediff_feature.available():
1278
1307
            from bzrlib._patiencediff_c import unique_lcs_c
1279
1308
            self.assertIs(unique_lcs_c,
1280
 
                          bzrlib.patiencediff.unique_lcs)
 
1309
                          patiencediff.unique_lcs)
1281
1310
        else:
1282
1311
            from bzrlib._patiencediff_py import unique_lcs_py
1283
1312
            self.assertIs(unique_lcs_py,
1284
 
                          bzrlib.patiencediff.unique_lcs)
 
1313
                          patiencediff.unique_lcs)
1285
1314
 
1286
1315
    def test_recurse_matches(self):
1287
 
        if CompiledPatienceDiffFeature.available():
 
1316
        if compiled_patiencediff_feature.available():
1288
1317
            from bzrlib._patiencediff_c import recurse_matches_c
1289
1318
            self.assertIs(recurse_matches_c,
1290
 
                          bzrlib.patiencediff.recurse_matches)
 
1319
                          patiencediff.recurse_matches)
1291
1320
        else:
1292
1321
            from bzrlib._patiencediff_py import recurse_matches_py
1293
1322
            self.assertIs(recurse_matches_py,
1294
 
                          bzrlib.patiencediff.recurse_matches)
1295
 
 
1296
 
 
1297
 
class TestDiffFromTool(TestCaseWithTransport):
 
1323
                          patiencediff.recurse_matches)
 
1324
 
 
1325
 
 
1326
class TestDiffFromTool(tests.TestCaseWithTransport):
1298
1327
 
1299
1328
    def test_from_string(self):
1300
 
        diff_obj = DiffFromTool.from_string('diff', None, None, None)
 
1329
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
1301
1330
        self.addCleanup(diff_obj.finish)
1302
1331
        self.assertEqual(['diff', '@old_path', '@new_path'],
1303
1332
            diff_obj.command_template)
1304
1333
 
1305
1334
    def test_from_string_u5(self):
1306
 
        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)
1307
1337
        self.addCleanup(diff_obj.finish)
1308
1338
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
1309
1339
                         diff_obj.command_template)
1310
1340
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1311
1341
                         diff_obj._get_command('old-path', 'new-path'))
1312
1342
 
 
1343
    def test_from_string_path_with_backslashes(self):
 
1344
        self.requireFeature(features.backslashdir_feature)
 
1345
        tool = 'C:\\Tools\\Diff.exe'
 
1346
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
 
1347
        self.addCleanup(diff_obj.finish)
 
1348
        self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
 
1349
                         diff_obj.command_template)
 
1350
        self.assertEqual(['C:\\Tools\\Diff.exe', 'old-path', 'new-path'],
 
1351
                         diff_obj._get_command('old-path', 'new-path'))
 
1352
 
1313
1353
    def test_execute(self):
1314
1354
        output = StringIO()
1315
 
        diff_obj = DiffFromTool(['python', '-c',
1316
 
                                 'print "@old_path @new_path"'],
1317
 
                                None, None, output)
 
1355
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1356
                                      'print "@old_path @new_path"'],
 
1357
                                     None, None, output)
1318
1358
        self.addCleanup(diff_obj.finish)
1319
1359
        diff_obj._execute('old', 'new')
1320
1360
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1321
1361
 
1322
1362
    def test_excute_missing(self):
1323
 
        diff_obj = DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1324
 
                                None, None, None)
 
1363
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
 
1364
                                     None, None, None)
1325
1365
        self.addCleanup(diff_obj.finish)
1326
 
        e = self.assertRaises(ExecutableMissing, diff_obj._execute, 'old',
1327
 
                              'new')
 
1366
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
 
1367
                              'old', 'new')
1328
1368
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1329
1369
                         ' on this machine', str(e))
1330
1370
 
1340
1380
        basis_tree = tree.basis_tree()
1341
1381
        basis_tree.lock_read()
1342
1382
        self.addCleanup(basis_tree.unlock)
1343
 
        diff_obj = DiffFromTool(['python', '-c',
1344
 
                                 'print "@old_path @new_path"'],
1345
 
                                basis_tree, tree, output)
 
1383
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1384
                                      'print "@old_path @new_path"'],
 
1385
                                     basis_tree, tree, output)
1346
1386
        diff_obj._prepare_files('file-id', 'file', 'file')
1347
1387
        # The old content should be readonly
1348
1388
        self.assertReadableByAttrib(diff_obj._root, 'old\\file',
1365
1405
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
1366
1406
        tree.add('oldname', 'file-id')
1367
1407
        tree.add('oldname2', 'file2-id')
1368
 
        tree.commit('old tree', timestamp=0)
 
1408
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
1409
        tree.commit('old tree', timestamp=315532800)
1369
1410
        tree.rename_one('oldname', 'newname')
1370
1411
        tree.rename_one('oldname2', 'newname2')
1371
1412
        self.build_tree_contents([('tree/newname', 'newcontent')])
1375
1416
        self.addCleanup(old_tree.unlock)
1376
1417
        tree.lock_read()
1377
1418
        self.addCleanup(tree.unlock)
1378
 
        diff_obj = DiffFromTool(['python', '-c',
1379
 
                                 'print "@old_path @new_path"'],
1380
 
                                old_tree, tree, output)
 
1419
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1420
                                      'print "@old_path @new_path"'],
 
1421
                                     old_tree, tree, output)
1381
1422
        self.addCleanup(diff_obj.finish)
1382
1423
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1383
1424
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1384
1425
                                                     'newname')
1385
1426
        self.assertContainsRe(old_path, 'old/oldname$')
1386
 
        self.assertEqual(0, os.stat(old_path).st_mtime)
 
1427
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
1387
1428
        self.assertContainsRe(new_path, 'tree/newname$')
1388
1429
        self.assertFileEqual('oldcontent', old_path)
1389
1430
        self.assertFileEqual('newcontent', new_path)
1393
1434
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1394
1435
 
1395
1436
 
1396
 
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)
1397
1445
 
1398
1446
    def test_basic(self):
1399
1447
        tree = self.make_branch_and_tree('tree')
1400
1448
        (old_tree, new_tree,
1401
1449
         old_branch, new_branch,
1402
 
         specific_files, extra_trees) = \
1403
 
            get_trees_and_branches_to_diff(['tree'], None, None, None)
 
1450
         specific_files, extra_trees) = self.call_gtabtd(
 
1451
             ['tree'], None, None, None)
1404
1452
 
1405
 
        self.assertIsInstance(old_tree, RevisionTree)
1406
 
        #print dir (old_tree)
1407
 
        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())
1408
1456
        self.assertEqual(tree.basedir, new_tree.basedir)
1409
1457
        self.assertEqual(tree.branch.base, old_branch.base)
1410
1458
        self.assertEqual(tree.branch.base, new_branch.base)
1419
1467
        self.build_tree_contents([('tree/file', 'newcontent')])
1420
1468
        tree.commit('new tree', timestamp=0, rev_id="new-id")
1421
1469
 
1422
 
        revisions = [RevisionSpec.from_string('1'),
1423
 
                     RevisionSpec.from_string('2')]
 
1470
        revisions = [revisionspec.RevisionSpec.from_string('1'),
 
1471
                     revisionspec.RevisionSpec.from_string('2')]
1424
1472
        (old_tree, new_tree,
1425
1473
         old_branch, new_branch,
1426
 
         specific_files, extra_trees) = \
1427
 
            get_trees_and_branches_to_diff(['tree'], revisions, None, None)
 
1474
         specific_files, extra_trees) = self.call_gtabtd(
 
1475
            ['tree'], revisions, None, None)
1428
1476
 
1429
 
        self.assertIsInstance(old_tree, RevisionTree)
 
1477
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1430
1478
        self.assertEqual("old-id", old_tree.get_revision_id())
1431
 
        self.assertIsInstance(new_tree, RevisionTree)
 
1479
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
1432
1480
        self.assertEqual("new-id", new_tree.get_revision_id())
1433
1481
        self.assertEqual(tree.branch.base, old_branch.base)
1434
1482
        self.assertEqual(tree.branch.base, new_branch.base)
1435
1483
        self.assertIs(None, specific_files)
1436
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