/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: John Arbash Meinel
  • Date: 2011-04-20 09:46:28 UTC
  • mfrom: (5609.33.4 2.3)
  • mto: (5609.33.5 2.3)
  • mto: This revision was merged to the branch mainline in revision 5811.
  • Revision ID: john@arbash-meinel.com-20110420094628-l0bafq1lwb6ib1v2
Merge lp:bzr/2.3 @ 5640 so we can update the release notes (aka NEWS)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
18
 
import os.path
19
18
from cStringIO import StringIO
20
 
import errno
21
19
import subprocess
22
20
import sys
23
 
from tempfile import TemporaryFile
 
21
import tempfile
24
22
 
25
 
from bzrlib import tests
26
 
from bzrlib.diff import (
27
 
    DiffFromTool,
28
 
    DiffPath,
29
 
    DiffSymlink,
30
 
    DiffTree,
31
 
    DiffText,
32
 
    external_diff,
33
 
    internal_diff,
34
 
    show_diff_trees,
35
 
    get_trees_and_branches_to_diff,
 
23
from bzrlib import (
 
24
    diff,
 
25
    errors,
 
26
    osutils,
 
27
    patiencediff,
 
28
    _patiencediff_py,
 
29
    revision as _mod_revision,
 
30
    revisionspec,
 
31
    revisiontree,
 
32
    tests,
 
33
    transform,
36
34
    )
37
 
from bzrlib.errors import BinaryFile, NoDiff, ExecutableMissing
38
 
import bzrlib.osutils as osutils
39
 
import bzrlib.revision as _mod_revision
40
 
import bzrlib.transform as transform
41
 
import bzrlib.patiencediff
42
 
import bzrlib._patiencediff_py
43
 
from bzrlib.tests import (Feature, TestCase, TestCaseWithTransport,
44
 
                          TestCaseInTempDir, TestSkipped)
45
 
from bzrlib.revisiontree import RevisionTree
46
 
from bzrlib.revisionspec import RevisionSpec
47
 
 
48
 
 
49
 
class _AttribFeature(Feature):
 
35
from bzrlib.symbol_versioning import deprecated_in
 
36
from bzrlib.tests import features
 
37
from bzrlib.tests.blackbox.test_diff import subst_dates
 
38
 
 
39
 
 
40
class _AttribFeature(tests.Feature):
50
41
 
51
42
    def _probe(self):
52
43
        if (sys.platform not in ('cygwin', 'win32')):
69
60
 
70
61
def udiff_lines(old, new, allow_binary=False):
71
62
    output = StringIO()
72
 
    internal_diff('old', old, 'new', new, output, allow_binary)
 
63
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
73
64
    output.seek(0, 0)
74
65
    return output.readlines()
75
66
 
79
70
        # StringIO has no fileno, so it tests a different codepath
80
71
        output = StringIO()
81
72
    else:
82
 
        output = TemporaryFile()
 
73
        output = tempfile.TemporaryFile()
83
74
    try:
84
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
85
 
    except NoDiff:
86
 
        raise TestSkipped('external "diff" not present to test')
 
75
        diff.external_diff('old', old, 'new', new, output, diff_opts=['-u'])
 
76
    except errors.NoDiff:
 
77
        raise tests.TestSkipped('external "diff" not present to test')
87
78
    output.seek(0, 0)
88
79
    lines = output.readlines()
89
80
    output.close()
90
81
    return lines
91
82
 
92
83
 
93
 
class TestDiff(TestCase):
 
84
class TestDiff(tests.TestCase):
94
85
 
95
86
    def test_add_nl(self):
96
87
        """diff generates a valid diff for patches that add a newline"""
132
123
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
133
124
 
134
125
    def test_binary_lines(self):
135
 
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
136
 
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
137
 
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
138
 
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
 
126
        empty = []
 
127
        uni_lines = [1023 * 'a' + '\x00']
 
128
        self.assertRaises(errors.BinaryFile, udiff_lines, uni_lines , empty)
 
129
        self.assertRaises(errors.BinaryFile, udiff_lines, empty, uni_lines)
 
130
        udiff_lines(uni_lines , empty, allow_binary=True)
 
131
        udiff_lines(empty, uni_lines, allow_binary=True)
139
132
 
140
133
    def test_external_diff(self):
141
134
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
151
144
        self.check_patch(lines)
152
145
 
153
146
    def test_external_diff_binary_lang_c(self):
154
 
        old_env = {}
155
147
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
156
 
            old_env[lang] = osutils.set_or_unset_env(lang, 'C')
157
 
        try:
158
 
            lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
159
 
            # Older versions of diffutils say "Binary files", newer
160
 
            # versions just say "Files".
161
 
            self.assertContainsRe(lines[0],
162
 
                                  '(Binary f|F)iles old and new differ\n')
163
 
            self.assertEquals(lines[1:], ['\n'])
164
 
        finally:
165
 
            for lang, old_val in old_env.iteritems():
166
 
                osutils.set_or_unset_env(lang, old_val)
 
148
            self.overrideEnv(lang, 'C')
 
149
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
 
150
        # Older versions of diffutils say "Binary files", newer
 
151
        # versions just say "Files".
 
152
        self.assertContainsRe(lines[0], '(Binary f|F)iles old and new differ\n')
 
153
        self.assertEquals(lines[1:], ['\n'])
167
154
 
168
155
    def test_no_external_diff(self):
169
156
        """Check that NoDiff is raised when diff is not available"""
170
 
        # Use os.environ['PATH'] to make sure no 'diff' command is available
171
 
        orig_path = os.environ['PATH']
172
 
        try:
173
 
            os.environ['PATH'] = ''
174
 
            self.assertRaises(NoDiff, external_diff,
175
 
                              'old', ['boo\n'], 'new', ['goo\n'],
176
 
                              StringIO(), diff_opts=['-u'])
177
 
        finally:
178
 
            os.environ['PATH'] = orig_path
 
157
        # Make sure no 'diff' command is available
 
158
        # XXX: Weird, using None instead of '' breaks the test -- vila 20101216
 
159
        self.overrideEnv('PATH', '')
 
160
        self.assertRaises(errors.NoDiff, diff.external_diff,
 
161
                          'old', ['boo\n'], 'new', ['goo\n'],
 
162
                          StringIO(), diff_opts=['-u'])
179
163
 
180
164
    def test_internal_diff_default(self):
181
165
        # Default internal diff encoding is utf8
182
166
        output = StringIO()
183
 
        internal_diff(u'old_\xb5', ['old_text\n'],
184
 
                    u'new_\xe5', ['new_text\n'], output)
 
167
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
168
                           u'new_\xe5', ['new_text\n'], output)
185
169
        lines = output.getvalue().splitlines(True)
186
170
        self.check_patch(lines)
187
171
        self.assertEquals(['--- old_\xc2\xb5\n',
195
179
 
196
180
    def test_internal_diff_utf8(self):
197
181
        output = StringIO()
198
 
        internal_diff(u'old_\xb5', ['old_text\n'],
199
 
                    u'new_\xe5', ['new_text\n'], output,
200
 
                    path_encoding='utf8')
 
182
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
183
                           u'new_\xe5', ['new_text\n'], output,
 
184
                           path_encoding='utf8')
201
185
        lines = output.getvalue().splitlines(True)
202
186
        self.check_patch(lines)
203
187
        self.assertEquals(['--- old_\xc2\xb5\n',
211
195
 
212
196
    def test_internal_diff_iso_8859_1(self):
213
197
        output = StringIO()
214
 
        internal_diff(u'old_\xb5', ['old_text\n'],
215
 
                    u'new_\xe5', ['new_text\n'], output,
216
 
                    path_encoding='iso-8859-1')
 
198
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
199
                           u'new_\xe5', ['new_text\n'], output,
 
200
                           path_encoding='iso-8859-1')
217
201
        lines = output.getvalue().splitlines(True)
218
202
        self.check_patch(lines)
219
203
        self.assertEquals(['--- old_\xb5\n',
227
211
 
228
212
    def test_internal_diff_no_content(self):
229
213
        output = StringIO()
230
 
        internal_diff(u'old', [], u'new', [], output)
 
214
        diff.internal_diff(u'old', [], u'new', [], output)
231
215
        self.assertEqual('', output.getvalue())
232
216
 
233
217
    def test_internal_diff_no_changes(self):
234
218
        output = StringIO()
235
 
        internal_diff(u'old', ['text\n', 'contents\n'],
236
 
                      u'new', ['text\n', 'contents\n'],
237
 
                      output)
 
219
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
 
220
                           u'new', ['text\n', 'contents\n'],
 
221
                           output)
238
222
        self.assertEqual('', output.getvalue())
239
223
 
240
224
    def test_internal_diff_returns_bytes(self):
241
225
        import StringIO
242
226
        output = StringIO.StringIO()
243
 
        internal_diff(u'old_\xb5', ['old_text\n'],
244
 
                    u'new_\xe5', ['new_text\n'], output)
 
227
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
228
                            u'new_\xe5', ['new_text\n'], output)
245
229
        self.failUnless(isinstance(output.getvalue(), str),
246
230
            'internal_diff should return bytestrings')
247
231
 
248
232
 
249
 
class TestDiffFiles(TestCaseInTempDir):
 
233
class TestDiffFiles(tests.TestCaseInTempDir):
250
234
 
251
235
    def test_external_diff_binary(self):
252
236
        """The output when using external diff should use diff's i18n error"""
265
249
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
266
250
 
267
251
 
268
 
class TestShowDiffTreesHelper(TestCaseWithTransport):
 
252
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
269
253
    """Has a helper for running show_diff_trees"""
270
254
 
271
255
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
274
258
            extra_trees = (working_tree,)
275
259
        else:
276
260
            extra_trees = ()
277
 
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
278
 
                        extra_trees=extra_trees, old_label='old/',
279
 
                        new_label='new/')
 
261
        diff.show_diff_trees(tree1, tree2, output,
 
262
                             specific_files=specific_files,
 
263
                             extra_trees=extra_trees, old_label='old/',
 
264
                             new_label='new/')
280
265
        return output.getvalue()
281
266
 
282
267
 
421
406
        tree.commit('one', rev_id='rev-1')
422
407
 
423
408
        self.build_tree_contents([('tree/file', 'new contents\n')])
424
 
        diff = self.get_diff(tree.basis_tree(), tree)
425
 
        self.assertContainsRe(diff, "=== modified file 'file'\n")
426
 
        self.assertContainsRe(diff, '--- old/file\t')
427
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/file\t')
428
 
        self.assertContainsRe(diff, '-contents\n'
429
 
                                    '\\+new contents\n')
 
409
        d = self.get_diff(tree.basis_tree(), tree)
 
410
        self.assertContainsRe(d, "=== modified file 'file'\n")
 
411
        self.assertContainsRe(d, '--- old/file\t')
 
412
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
 
413
        self.assertContainsRe(d, '-contents\n'
 
414
                                 '\\+new contents\n')
430
415
 
431
416
    def test_modified_file_in_renamed_dir(self):
432
417
        """Test when a file is modified in a renamed directory."""
438
423
 
439
424
        tree.rename_one('dir', 'other')
440
425
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
441
 
        diff = self.get_diff(tree.basis_tree(), tree)
442
 
        self.assertContainsRe(diff, "=== renamed directory 'dir' => 'other'\n")
443
 
        self.assertContainsRe(diff, "=== modified file 'other/file'\n")
 
426
        d = self.get_diff(tree.basis_tree(), tree)
 
427
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
 
428
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
444
429
        # XXX: This is technically incorrect, because it used to be at another
445
430
        # location. What to do?
446
 
        self.assertContainsRe(diff, '--- old/dir/file\t')
447
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/other/file\t')
448
 
        self.assertContainsRe(diff, '-contents\n'
449
 
                                    '\\+new contents\n')
 
431
        self.assertContainsRe(d, '--- old/dir/file\t')
 
432
        self.assertContainsRe(d, '\\+\\+\\+ new/other/file\t')
 
433
        self.assertContainsRe(d, '-contents\n'
 
434
                                 '\\+new contents\n')
450
435
 
451
436
    def test_renamed_directory(self):
452
437
        """Test when only a directory is only renamed."""
457
442
        tree.commit('one', rev_id='rev-1')
458
443
 
459
444
        tree.rename_one('dir', 'newdir')
460
 
        diff = self.get_diff(tree.basis_tree(), tree)
 
445
        d = self.get_diff(tree.basis_tree(), tree)
461
446
        # Renaming a directory should be a single "you renamed this dir" even
462
447
        # when there are files inside.
463
 
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
 
448
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
464
449
 
465
450
    def test_renamed_file(self):
466
451
        """Test when a file is only renamed."""
470
455
        tree.commit('one', rev_id='rev-1')
471
456
 
472
457
        tree.rename_one('file', 'newname')
473
 
        diff = self.get_diff(tree.basis_tree(), tree)
474
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
 
458
        d = self.get_diff(tree.basis_tree(), tree)
 
459
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
475
460
        # We shouldn't have a --- or +++ line, because there is no content
476
461
        # change
477
 
        self.assertNotContainsRe(diff, '---')
 
462
        self.assertNotContainsRe(d, '---')
478
463
 
479
464
    def test_renamed_and_modified_file(self):
480
465
        """Test when a file is only renamed."""
485
470
 
486
471
        tree.rename_one('file', 'newname')
487
472
        self.build_tree_contents([('tree/newname', 'new contents\n')])
488
 
        diff = self.get_diff(tree.basis_tree(), tree)
489
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
490
 
        self.assertContainsRe(diff, '--- old/file\t')
491
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/newname\t')
492
 
        self.assertContainsRe(diff, '-contents\n'
493
 
                                    '\\+new contents\n')
 
473
        d = self.get_diff(tree.basis_tree(), tree)
 
474
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
 
475
        self.assertContainsRe(d, '--- old/file\t')
 
476
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
 
477
        self.assertContainsRe(d, '-contents\n'
 
478
                                 '\\+new contents\n')
494
479
 
495
480
 
496
481
    def test_internal_diff_exec_property(self):
515
500
        tree.rename_one('c', 'new-c')
516
501
        tree.rename_one('d', 'new-d')
517
502
 
518
 
        diff = self.get_diff(tree.basis_tree(), tree)
519
 
 
520
 
        self.assertContainsRe(diff, r"file 'a'.*\(properties changed:.*\+x to -x.*\)")
521
 
        self.assertContainsRe(diff, r"file 'b'.*\(properties changed:.*-x to \+x.*\)")
522
 
        self.assertContainsRe(diff, r"file 'c'.*\(properties changed:.*\+x to -x.*\)")
523
 
        self.assertContainsRe(diff, r"file 'd'.*\(properties changed:.*-x to \+x.*\)")
524
 
        self.assertNotContainsRe(diff, r"file 'e'")
525
 
        self.assertNotContainsRe(diff, r"file 'f'")
526
 
 
 
503
        d = self.get_diff(tree.basis_tree(), tree)
 
504
 
 
505
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
 
506
                                  ".*\+x to -x.*\)")
 
507
        self.assertContainsRe(d, r"file 'b'.*\(properties changed:"
 
508
                                  ".*-x to \+x.*\)")
 
509
        self.assertContainsRe(d, r"file 'c'.*\(properties changed:"
 
510
                                  ".*\+x to -x.*\)")
 
511
        self.assertContainsRe(d, r"file 'd'.*\(properties changed:"
 
512
                                  ".*-x to \+x.*\)")
 
513
        self.assertNotContainsRe(d, r"file 'e'")
 
514
        self.assertNotContainsRe(d, r"file 'f'")
527
515
 
528
516
    def test_binary_unicode_filenames(self):
529
517
        """Test that contents of files are *not* encoded in UTF-8 when there
544
532
        tree.add([alpha], ['file-id'])
545
533
        tree.add([omega], ['file-id-2'])
546
534
        diff_content = StringIO()
547
 
        show_diff_trees(tree.basis_tree(), tree, diff_content)
548
 
        diff = diff_content.getvalue()
549
 
        self.assertContainsRe(diff, r"=== added file '%s'" % alpha_utf8)
550
 
        self.assertContainsRe(
551
 
            diff, "Binary files a/%s.*and b/%s.* differ\n" % (alpha_utf8, alpha_utf8))
552
 
        self.assertContainsRe(diff, r"=== added file '%s'" % omega_utf8)
553
 
        self.assertContainsRe(diff, r"--- a/%s" % (omega_utf8,))
554
 
        self.assertContainsRe(diff, r"\+\+\+ b/%s" % (omega_utf8,))
 
535
        diff.show_diff_trees(tree.basis_tree(), tree, diff_content)
 
536
        d = diff_content.getvalue()
 
537
        self.assertContainsRe(d, r"=== added file '%s'" % alpha_utf8)
 
538
        self.assertContainsRe(d, "Binary files a/%s.*and b/%s.* differ\n"
 
539
                              % (alpha_utf8, alpha_utf8))
 
540
        self.assertContainsRe(d, r"=== added file '%s'" % omega_utf8)
 
541
        self.assertContainsRe(d, r"--- a/%s" % (omega_utf8,))
 
542
        self.assertContainsRe(d, r"\+\+\+ b/%s" % (omega_utf8,))
555
543
 
556
544
    def test_unicode_filename(self):
557
545
        """Test when the filename are unicode."""
576
564
        tree.add(['add_'+alpha], ['file-id'])
577
565
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
578
566
 
579
 
        diff = self.get_diff(tree.basis_tree(), tree)
580
 
        self.assertContainsRe(diff,
 
567
        d = self.get_diff(tree.basis_tree(), tree)
 
568
        self.assertContainsRe(d,
581
569
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
582
 
        self.assertContainsRe(diff, "=== added file 'add_%s'"%autf8)
583
 
        self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
584
 
        self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
585
 
 
586
 
 
587
 
class DiffWasIs(DiffPath):
 
570
        self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
 
571
        self.assertContainsRe(d, "=== modified file 'mod_%s'"%autf8)
 
572
        self.assertContainsRe(d, "=== removed file 'del_%s'"%autf8)
 
573
 
 
574
    def test_unicode_filename_path_encoding(self):
 
575
        """Test for bug #382699: unicode filenames on Windows should be shown
 
576
        in user encoding.
 
577
        """
 
578
        self.requireFeature(tests.UnicodeFilenameFeature)
 
579
        # The word 'test' in Russian
 
580
        _russian_test = u'\u0422\u0435\u0441\u0442'
 
581
        directory = _russian_test + u'/'
 
582
        test_txt = _russian_test + u'.txt'
 
583
        u1234 = u'\u1234.txt'
 
584
 
 
585
        tree = self.make_branch_and_tree('.')
 
586
        self.build_tree_contents([
 
587
            (test_txt, 'foo\n'),
 
588
            (u1234, 'foo\n'),
 
589
            (directory, None),
 
590
            ])
 
591
        tree.add([test_txt, u1234, directory])
 
592
 
 
593
        sio = StringIO()
 
594
        diff.show_diff_trees(tree.basis_tree(), tree, sio,
 
595
            path_encoding='cp1251')
 
596
 
 
597
        output = subst_dates(sio.getvalue())
 
598
        shouldbe = ('''\
 
599
=== added directory '%(directory)s'
 
600
=== added file '%(test_txt)s'
 
601
--- a/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
602
+++ b/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
603
@@ -0,0 +1,1 @@
 
604
+foo
 
605
 
 
606
=== added file '?.txt'
 
607
--- a/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
608
+++ b/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
609
@@ -0,0 +1,1 @@
 
610
+foo
 
611
 
 
612
''' % {'directory': _russian_test.encode('cp1251'),
 
613
       'test_txt': test_txt.encode('cp1251'),
 
614
      })
 
615
        self.assertEqualDiff(output, shouldbe)
 
616
 
 
617
 
 
618
class DiffWasIs(diff.DiffPath):
588
619
 
589
620
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
590
621
        self.to_file.write('was: ')
594
625
        pass
595
626
 
596
627
 
597
 
class TestDiffTree(TestCaseWithTransport):
 
628
class TestDiffTree(tests.TestCaseWithTransport):
598
629
 
599
630
    def setUp(self):
600
 
        TestCaseWithTransport.setUp(self)
 
631
        super(TestDiffTree, self).setUp()
601
632
        self.old_tree = self.make_branch_and_tree('old-tree')
602
633
        self.old_tree.lock_write()
603
634
        self.addCleanup(self.old_tree.unlock)
604
635
        self.new_tree = self.make_branch_and_tree('new-tree')
605
636
        self.new_tree.lock_write()
606
637
        self.addCleanup(self.new_tree.unlock)
607
 
        self.differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
638
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
608
639
 
609
640
    def test_diff_text(self):
610
641
        self.build_tree_contents([('old-tree/olddir/',),
615
646
                                  ('new-tree/newdir/newfile', 'new\n')])
616
647
        self.new_tree.add('newdir')
617
648
        self.new_tree.add('newdir/newfile', 'file-id')
618
 
        differ = DiffText(self.old_tree, self.new_tree, StringIO())
 
649
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
619
650
        differ.diff_text('file-id', None, 'old label', 'new label')
620
651
        self.assertEqual(
621
652
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
650
681
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
651
682
 
652
683
    def test_diff_symlink(self):
653
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
684
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
654
685
        differ.diff_symlink('old target', None)
655
686
        self.assertEqual("=== target was 'old target'\n",
656
687
                         differ.to_file.getvalue())
657
688
 
658
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
689
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
659
690
        differ.diff_symlink(None, 'new target')
660
691
        self.assertEqual("=== target is 'new target'\n",
661
692
                         differ.to_file.getvalue())
662
693
 
663
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
694
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
664
695
        differ.diff_symlink('old target', 'new target')
665
696
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
666
697
                         differ.to_file.getvalue())
716
747
 
717
748
    def test_register_diff(self):
718
749
        self.create_old_new()
719
 
        old_diff_factories = DiffTree.diff_factories
720
 
        DiffTree.diff_factories=old_diff_factories[:]
721
 
        DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
 
750
        old_diff_factories = diff.DiffTree.diff_factories
 
751
        diff.DiffTree.diff_factories=old_diff_factories[:]
 
752
        diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
722
753
        try:
723
 
            differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
754
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
724
755
        finally:
725
 
            DiffTree.diff_factories = old_diff_factories
 
756
            diff.DiffTree.diff_factories = old_diff_factories
726
757
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
727
758
        self.assertNotContainsRe(
728
759
            differ.to_file.getvalue(),
733
764
 
734
765
    def test_extra_factories(self):
735
766
        self.create_old_new()
736
 
        differ = DiffTree(self.old_tree, self.new_tree, StringIO(),
737
 
                            extra_factories=[DiffWasIs.from_diff_tree])
 
767
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
 
768
                               extra_factories=[DiffWasIs.from_diff_tree])
738
769
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
739
770
        self.assertNotContainsRe(
740
771
            differ.to_file.getvalue(),
753
784
            '.*a-file(.|\n)*b-file')
754
785
 
755
786
 
756
 
class TestPatienceDiffLib(TestCase):
 
787
class TestPatienceDiffLib(tests.TestCase):
757
788
 
758
789
    def setUp(self):
759
790
        super(TestPatienceDiffLib, self).setUp()
760
 
        self._unique_lcs = bzrlib._patiencediff_py.unique_lcs_py
761
 
        self._recurse_matches = bzrlib._patiencediff_py.recurse_matches_py
 
791
        self._unique_lcs = _patiencediff_py.unique_lcs_py
 
792
        self._recurse_matches = _patiencediff_py.recurse_matches_py
762
793
        self._PatienceSequenceMatcher = \
763
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
794
            _patiencediff_py.PatienceSequenceMatcher_py
764
795
 
765
796
    def test_diff_unicode_string(self):
766
797
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
1073
1104
                 'how are you today?\n']
1074
1105
        txt_b = ['hello there\n',
1075
1106
                 'how are you today?\n']
1076
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1107
        unified_diff = patiencediff.unified_diff
1077
1108
        psm = self._PatienceSequenceMatcher
1078
1109
        self.assertEquals(['--- \n',
1079
1110
                           '+++ \n',
1127
1158
                 'how are you today?\n']
1128
1159
        txt_b = ['hello there\n',
1129
1160
                 'how are you today?\n']
1130
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1161
        unified_diff = patiencediff.unified_diff
1131
1162
        psm = self._PatienceSequenceMatcher
1132
1163
        self.assertEquals(['--- a\t2008-08-08\n',
1133
1164
                           '+++ b\t2008-09-09\n',
1149
1180
 
1150
1181
    def setUp(self):
1151
1182
        super(TestPatienceDiffLib_c, self).setUp()
1152
 
        import bzrlib._patiencediff_c
1153
 
        self._unique_lcs = bzrlib._patiencediff_c.unique_lcs_c
1154
 
        self._recurse_matches = bzrlib._patiencediff_c.recurse_matches_c
 
1183
        from bzrlib import _patiencediff_c
 
1184
        self._unique_lcs = _patiencediff_c.unique_lcs_c
 
1185
        self._recurse_matches = _patiencediff_c.recurse_matches_c
1155
1186
        self._PatienceSequenceMatcher = \
1156
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
 
1187
            _patiencediff_c.PatienceSequenceMatcher_c
1157
1188
 
1158
1189
    def test_unhashable(self):
1159
1190
        """We should get a proper exception here."""
1169
1200
                                         None, ['valid'], ['valid', []])
1170
1201
 
1171
1202
 
1172
 
class TestPatienceDiffLibFiles(TestCaseInTempDir):
 
1203
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1173
1204
 
1174
1205
    def setUp(self):
1175
1206
        super(TestPatienceDiffLibFiles, self).setUp()
1176
1207
        self._PatienceSequenceMatcher = \
1177
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
1208
            _patiencediff_py.PatienceSequenceMatcher_py
1178
1209
 
1179
1210
    def test_patience_unified_diff_files(self):
1180
1211
        txt_a = ['hello there\n',
1185
1216
        open('a1', 'wb').writelines(txt_a)
1186
1217
        open('b1', 'wb').writelines(txt_b)
1187
1218
 
1188
 
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
 
1219
        unified_diff_files = patiencediff.unified_diff_files
1189
1220
        psm = self._PatienceSequenceMatcher
1190
1221
        self.assertEquals(['--- a1\n',
1191
1222
                           '+++ b1\n',
1245
1276
 
1246
1277
    def setUp(self):
1247
1278
        super(TestPatienceDiffLibFiles_c, self).setUp()
1248
 
        import bzrlib._patiencediff_c
 
1279
        from bzrlib import _patiencediff_c
1249
1280
        self._PatienceSequenceMatcher = \
1250
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
1251
 
 
1252
 
 
1253
 
class TestUsingCompiledIfAvailable(TestCase):
 
1281
            _patiencediff_c.PatienceSequenceMatcher_c
 
1282
 
 
1283
 
 
1284
class TestUsingCompiledIfAvailable(tests.TestCase):
1254
1285
 
1255
1286
    def test_PatienceSequenceMatcher(self):
1256
1287
        if compiled_patiencediff_feature.available():
1257
1288
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1258
1289
            self.assertIs(PatienceSequenceMatcher_c,
1259
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1290
                          patiencediff.PatienceSequenceMatcher)
1260
1291
        else:
1261
1292
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1262
1293
            self.assertIs(PatienceSequenceMatcher_py,
1263
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1294
                          patiencediff.PatienceSequenceMatcher)
1264
1295
 
1265
1296
    def test_unique_lcs(self):
1266
1297
        if compiled_patiencediff_feature.available():
1267
1298
            from bzrlib._patiencediff_c import unique_lcs_c
1268
1299
            self.assertIs(unique_lcs_c,
1269
 
                          bzrlib.patiencediff.unique_lcs)
 
1300
                          patiencediff.unique_lcs)
1270
1301
        else:
1271
1302
            from bzrlib._patiencediff_py import unique_lcs_py
1272
1303
            self.assertIs(unique_lcs_py,
1273
 
                          bzrlib.patiencediff.unique_lcs)
 
1304
                          patiencediff.unique_lcs)
1274
1305
 
1275
1306
    def test_recurse_matches(self):
1276
1307
        if compiled_patiencediff_feature.available():
1277
1308
            from bzrlib._patiencediff_c import recurse_matches_c
1278
1309
            self.assertIs(recurse_matches_c,
1279
 
                          bzrlib.patiencediff.recurse_matches)
 
1310
                          patiencediff.recurse_matches)
1280
1311
        else:
1281
1312
            from bzrlib._patiencediff_py import recurse_matches_py
1282
1313
            self.assertIs(recurse_matches_py,
1283
 
                          bzrlib.patiencediff.recurse_matches)
1284
 
 
1285
 
 
1286
 
class TestDiffFromTool(TestCaseWithTransport):
 
1314
                          patiencediff.recurse_matches)
 
1315
 
 
1316
 
 
1317
class TestDiffFromTool(tests.TestCaseWithTransport):
1287
1318
 
1288
1319
    def test_from_string(self):
1289
 
        diff_obj = DiffFromTool.from_string('diff', None, None, None)
 
1320
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
1290
1321
        self.addCleanup(diff_obj.finish)
1291
1322
        self.assertEqual(['diff', '@old_path', '@new_path'],
1292
1323
            diff_obj.command_template)
1293
1324
 
1294
1325
    def test_from_string_u5(self):
1295
 
        diff_obj = DiffFromTool.from_string('diff -u\\ 5', None, None, None)
 
1326
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
 
1327
                                                 None, None, None)
1296
1328
        self.addCleanup(diff_obj.finish)
1297
1329
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
1298
1330
                         diff_obj.command_template)
1299
1331
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1300
1332
                         diff_obj._get_command('old-path', 'new-path'))
1301
1333
 
 
1334
    def test_from_string_path_with_backslashes(self):
 
1335
        self.requireFeature(features.backslashdir_feature)
 
1336
        tool = 'C:\\Tools\\Diff.exe'
 
1337
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
 
1338
        self.addCleanup(diff_obj.finish)
 
1339
        self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
 
1340
                         diff_obj.command_template)
 
1341
        self.assertEqual(['C:\\Tools\\Diff.exe', 'old-path', 'new-path'],
 
1342
                         diff_obj._get_command('old-path', 'new-path'))
 
1343
 
1302
1344
    def test_execute(self):
1303
1345
        output = StringIO()
1304
 
        diff_obj = DiffFromTool(['python', '-c',
1305
 
                                 'print "@old_path @new_path"'],
1306
 
                                None, None, output)
 
1346
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1347
                                      'print "@old_path @new_path"'],
 
1348
                                     None, None, output)
1307
1349
        self.addCleanup(diff_obj.finish)
1308
1350
        diff_obj._execute('old', 'new')
1309
1351
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1310
1352
 
1311
1353
    def test_excute_missing(self):
1312
 
        diff_obj = DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1313
 
                                None, None, None)
 
1354
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
 
1355
                                     None, None, None)
1314
1356
        self.addCleanup(diff_obj.finish)
1315
 
        e = self.assertRaises(ExecutableMissing, diff_obj._execute, 'old',
1316
 
                              'new')
 
1357
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
 
1358
                              'old', 'new')
1317
1359
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1318
1360
                         ' on this machine', str(e))
1319
1361
 
1329
1371
        basis_tree = tree.basis_tree()
1330
1372
        basis_tree.lock_read()
1331
1373
        self.addCleanup(basis_tree.unlock)
1332
 
        diff_obj = DiffFromTool(['python', '-c',
1333
 
                                 'print "@old_path @new_path"'],
1334
 
                                basis_tree, tree, output)
 
1374
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1375
                                      'print "@old_path @new_path"'],
 
1376
                                     basis_tree, tree, output)
1335
1377
        diff_obj._prepare_files('file-id', 'file', 'file')
1336
1378
        # The old content should be readonly
1337
1379
        self.assertReadableByAttrib(diff_obj._root, 'old\\file',
1354
1396
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
1355
1397
        tree.add('oldname', 'file-id')
1356
1398
        tree.add('oldname2', 'file2-id')
1357
 
        tree.commit('old tree', timestamp=0)
 
1399
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
1400
        tree.commit('old tree', timestamp=315532800)
1358
1401
        tree.rename_one('oldname', 'newname')
1359
1402
        tree.rename_one('oldname2', 'newname2')
1360
1403
        self.build_tree_contents([('tree/newname', 'newcontent')])
1364
1407
        self.addCleanup(old_tree.unlock)
1365
1408
        tree.lock_read()
1366
1409
        self.addCleanup(tree.unlock)
1367
 
        diff_obj = DiffFromTool(['python', '-c',
1368
 
                                 'print "@old_path @new_path"'],
1369
 
                                old_tree, tree, output)
 
1410
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1411
                                      'print "@old_path @new_path"'],
 
1412
                                     old_tree, tree, output)
1370
1413
        self.addCleanup(diff_obj.finish)
1371
1414
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1372
1415
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1373
1416
                                                     'newname')
1374
1417
        self.assertContainsRe(old_path, 'old/oldname$')
1375
 
        self.assertEqual(0, os.stat(old_path).st_mtime)
 
1418
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
1376
1419
        self.assertContainsRe(new_path, 'tree/newname$')
1377
1420
        self.assertFileEqual('oldcontent', old_path)
1378
1421
        self.assertFileEqual('newcontent', new_path)
1382
1425
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1383
1426
 
1384
1427
 
1385
 
class TestGetTreesAndBranchesToDiff(TestCaseWithTransport):
 
1428
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
 
1429
 
 
1430
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
 
1431
        """Call get_trees_and_branches_to_diff_locked.  Overridden by
 
1432
        TestGetTreesAndBranchesToDiff.
 
1433
        """
 
1434
        return diff.get_trees_and_branches_to_diff_locked(
 
1435
            path_list, revision_specs, old_url, new_url, self.addCleanup)
1386
1436
 
1387
1437
    def test_basic(self):
1388
1438
        tree = self.make_branch_and_tree('tree')
1389
1439
        (old_tree, new_tree,
1390
1440
         old_branch, new_branch,
1391
 
         specific_files, extra_trees) = \
1392
 
            get_trees_and_branches_to_diff(['tree'], None, None, None)
 
1441
         specific_files, extra_trees) = self.call_gtabtd(
 
1442
             ['tree'], None, None, None)
1393
1443
 
1394
 
        self.assertIsInstance(old_tree, RevisionTree)
1395
 
        #print dir (old_tree)
1396
 
        self.assertEqual(_mod_revision.NULL_REVISION, old_tree.get_revision_id())
 
1444
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
 
1445
        self.assertEqual(_mod_revision.NULL_REVISION,
 
1446
                         old_tree.get_revision_id())
1397
1447
        self.assertEqual(tree.basedir, new_tree.basedir)
1398
1448
        self.assertEqual(tree.branch.base, old_branch.base)
1399
1449
        self.assertEqual(tree.branch.base, new_branch.base)
1408
1458
        self.build_tree_contents([('tree/file', 'newcontent')])
1409
1459
        tree.commit('new tree', timestamp=0, rev_id="new-id")
1410
1460
 
1411
 
        revisions = [RevisionSpec.from_string('1'),
1412
 
                     RevisionSpec.from_string('2')]
 
1461
        revisions = [revisionspec.RevisionSpec.from_string('1'),
 
1462
                     revisionspec.RevisionSpec.from_string('2')]
1413
1463
        (old_tree, new_tree,
1414
1464
         old_branch, new_branch,
1415
 
         specific_files, extra_trees) = \
1416
 
            get_trees_and_branches_to_diff(['tree'], revisions, None, None)
 
1465
         specific_files, extra_trees) = self.call_gtabtd(
 
1466
            ['tree'], revisions, None, None)
1417
1467
 
1418
 
        self.assertIsInstance(old_tree, RevisionTree)
 
1468
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1419
1469
        self.assertEqual("old-id", old_tree.get_revision_id())
1420
 
        self.assertIsInstance(new_tree, RevisionTree)
 
1470
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
1421
1471
        self.assertEqual("new-id", new_tree.get_revision_id())
1422
1472
        self.assertEqual(tree.branch.base, old_branch.base)
1423
1473
        self.assertEqual(tree.branch.base, new_branch.base)
1424
1474
        self.assertIs(None, specific_files)
1425
1475
        self.assertEqual(tree.basedir, extra_trees[0].basedir)
 
1476
 
 
1477
 
 
1478
class TestGetTreesAndBranchesToDiff(TestGetTreesAndBranchesToDiffLocked):
 
1479
    """Apply the tests for get_trees_and_branches_to_diff_locked to the
 
1480
    deprecated get_trees_and_branches_to_diff function.
 
1481
    """
 
1482
 
 
1483
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
 
1484
        return self.applyDeprecated(
 
1485
            deprecated_in((2, 2, 0)), diff.get_trees_and_branches_to_diff,
 
1486
            path_list, revision_specs, old_url, new_url)
 
1487