~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Andrew Bennetts
  • Date: 2008-01-11 04:55:53 UTC
  • mto: This revision was merged to the branch mainline in revision 3175.
  • Revision ID: andrew.bennetts@canonical.com-20080111045553-g8rfanwmvy2bchtp
Enable use of smart revision streaming between repos with compatible models, not just between identical format repos.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
 
import sys
21
 
import tempfile
 
22
from tempfile import TemporaryFile
22
23
 
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,
 
24
from bzrlib import tests
 
25
from bzrlib.diff import (
 
26
    DiffFromTool,
 
27
    DiffPath,
 
28
    DiffSymlink,
 
29
    DiffTree,
 
30
    DiffText,
 
31
    external_diff,
 
32
    internal_diff,
 
33
    show_diff_trees,
34
34
    )
35
 
from bzrlib.symbol_versioning import deprecated_in
36
 
from bzrlib.tests import test_win32utils
37
 
 
38
 
 
39
 
class _AttribFeature(tests.Feature):
 
35
from bzrlib.errors import BinaryFile, NoDiff, ExecutableMissing
 
36
import bzrlib.osutils as osutils
 
37
import bzrlib.patiencediff
 
38
import bzrlib._patiencediff_py
 
39
from bzrlib.tests import (Feature, TestCase, TestCaseWithTransport,
 
40
                          TestCaseInTempDir, TestSkipped)
 
41
 
 
42
 
 
43
class _CompiledPatienceDiffFeature(Feature):
40
44
 
41
45
    def _probe(self):
42
 
        if (sys.platform not in ('cygwin', 'win32')):
43
 
            return False
44
46
        try:
45
 
            proc = subprocess.Popen(['attrib', '.'], stdout=subprocess.PIPE)
46
 
        except OSError, e:
 
47
            import bzrlib._patiencediff_c
 
48
        except ImportError:
47
49
            return False
48
 
        return (0 == proc.wait())
 
50
        return True
49
51
 
50
52
    def feature_name(self):
51
 
        return 'attrib Windows command-line tool'
52
 
 
53
 
AttribFeature = _AttribFeature()
54
 
 
55
 
 
56
 
compiled_patiencediff_feature = tests.ModuleAvailableFeature(
57
 
                                    'bzrlib._patiencediff_c')
58
 
 
 
53
        return 'bzrlib._patiencediff_c'
 
54
 
 
55
CompiledPatienceDiffFeature = _CompiledPatienceDiffFeature()
 
56
 
 
57
 
 
58
class _UnicodeFilename(Feature):
 
59
    """Does the filesystem support Unicode filenames?"""
 
60
 
 
61
    def _probe(self):
 
62
        try:
 
63
            os.stat(u'\u03b1')
 
64
        except UnicodeEncodeError:
 
65
            return False
 
66
        except (IOError, OSError):
 
67
            # The filesystem allows the Unicode filename but the file doesn't
 
68
            # exist.
 
69
            return True
 
70
        else:
 
71
            # The filesystem allows the Unicode filename and the file exists,
 
72
            # for some reason.
 
73
            return True
 
74
 
 
75
UnicodeFilename = _UnicodeFilename()
 
76
 
 
77
 
 
78
class TestUnicodeFilename(TestCase):
 
79
 
 
80
    def test_probe_passes(self):
 
81
        """UnicodeFilename._probe passes."""
 
82
        # We can't test much more than that because the behaviour depends
 
83
        # on the platform.
 
84
        UnicodeFilename._probe()
 
85
        
59
86
 
60
87
def udiff_lines(old, new, allow_binary=False):
61
88
    output = StringIO()
62
 
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
 
89
    internal_diff('old', old, 'new', new, output, allow_binary)
63
90
    output.seek(0, 0)
64
91
    return output.readlines()
65
92
 
69
96
        # StringIO has no fileno, so it tests a different codepath
70
97
        output = StringIO()
71
98
    else:
72
 
        output = tempfile.TemporaryFile()
 
99
        output = TemporaryFile()
73
100
    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')
 
101
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
 
102
    except NoDiff:
 
103
        raise TestSkipped('external "diff" not present to test')
77
104
    output.seek(0, 0)
78
105
    lines = output.readlines()
79
106
    output.close()
80
107
    return lines
81
108
 
82
109
 
83
 
class TestDiff(tests.TestCase):
 
110
class TestDiff(TestCase):
84
111
 
85
112
    def test_add_nl(self):
86
113
        """diff generates a valid diff for patches that add a newline"""
122
149
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
123
150
 
124
151
    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)
 
152
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
 
153
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
 
154
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
 
155
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
131
156
 
132
157
    def test_external_diff(self):
133
158
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
163
188
        orig_path = os.environ['PATH']
164
189
        try:
165
190
            os.environ['PATH'] = ''
166
 
            self.assertRaises(errors.NoDiff, diff.external_diff,
 
191
            self.assertRaises(NoDiff, external_diff,
167
192
                              'old', ['boo\n'], 'new', ['goo\n'],
168
193
                              StringIO(), diff_opts=['-u'])
169
194
        finally:
170
195
            os.environ['PATH'] = orig_path
171
 
 
 
196
        
172
197
    def test_internal_diff_default(self):
173
198
        # Default internal diff encoding is utf8
174
199
        output = StringIO()
175
 
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
176
 
                           u'new_\xe5', ['new_text\n'], output)
 
200
        internal_diff(u'old_\xb5', ['old_text\n'],
 
201
                    u'new_\xe5', ['new_text\n'], output)
177
202
        lines = output.getvalue().splitlines(True)
178
203
        self.check_patch(lines)
179
204
        self.assertEquals(['--- old_\xc2\xb5\n',
187
212
 
188
213
    def test_internal_diff_utf8(self):
189
214
        output = StringIO()
190
 
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
191
 
                           u'new_\xe5', ['new_text\n'], output,
192
 
                           path_encoding='utf8')
 
215
        internal_diff(u'old_\xb5', ['old_text\n'],
 
216
                    u'new_\xe5', ['new_text\n'], output,
 
217
                    path_encoding='utf8')
193
218
        lines = output.getvalue().splitlines(True)
194
219
        self.check_patch(lines)
195
220
        self.assertEquals(['--- old_\xc2\xb5\n',
203
228
 
204
229
    def test_internal_diff_iso_8859_1(self):
205
230
        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')
 
231
        internal_diff(u'old_\xb5', ['old_text\n'],
 
232
                    u'new_\xe5', ['new_text\n'], output,
 
233
                    path_encoding='iso-8859-1')
209
234
        lines = output.getvalue().splitlines(True)
210
235
        self.check_patch(lines)
211
236
        self.assertEquals(['--- old_\xb5\n',
219
244
 
220
245
    def test_internal_diff_no_content(self):
221
246
        output = StringIO()
222
 
        diff.internal_diff(u'old', [], u'new', [], output)
 
247
        internal_diff(u'old', [], u'new', [], output)
223
248
        self.assertEqual('', output.getvalue())
224
249
 
225
250
    def test_internal_diff_no_changes(self):
226
251
        output = StringIO()
227
 
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
228
 
                           u'new', ['text\n', 'contents\n'],
229
 
                           output)
 
252
        internal_diff(u'old', ['text\n', 'contents\n'],
 
253
                      u'new', ['text\n', 'contents\n'],
 
254
                      output)
230
255
        self.assertEqual('', output.getvalue())
231
256
 
232
257
    def test_internal_diff_returns_bytes(self):
233
258
        import StringIO
234
259
        output = StringIO.StringIO()
235
 
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
236
 
                            u'new_\xe5', ['new_text\n'], output)
 
260
        internal_diff(u'old_\xb5', ['old_text\n'],
 
261
                    u'new_\xe5', ['new_text\n'], output)
237
262
        self.failUnless(isinstance(output.getvalue(), str),
238
263
            'internal_diff should return bytestrings')
239
264
 
240
265
 
241
 
class TestDiffFiles(tests.TestCaseInTempDir):
 
266
class TestDiffFiles(TestCaseInTempDir):
242
267
 
243
268
    def test_external_diff_binary(self):
244
269
        """The output when using external diff should use diff's i18n error"""
257
282
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
258
283
 
259
284
 
260
 
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
 
285
class TestShowDiffTreesHelper(TestCaseWithTransport):
261
286
    """Has a helper for running show_diff_trees"""
262
287
 
263
288
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
266
291
            extra_trees = (working_tree,)
267
292
        else:
268
293
            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/')
 
294
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
 
295
                        extra_trees=extra_trees, old_label='old/',
 
296
                        new_label='new/')
273
297
        return output.getvalue()
274
298
 
275
299
 
340
364
+file2 contents at rev 3
341
365
 
342
366
''')
343
 
 
 
367
        
344
368
    def test_diff_add_files(self):
345
 
        tree1 = self.b.repository.revision_tree(_mod_revision.NULL_REVISION)
 
369
        tree1 = self.b.repository.revision_tree(None)
346
370
        tree2 = self.b.repository.revision_tree('rev-1')
347
371
        output = self.get_diff(tree1, tree2)
348
372
        # the files have the epoch time stamp for the tree in which
382
406
        self.wt.rename_one('file1', 'file1b')
383
407
        old_tree = self.b.repository.revision_tree('rev-1')
384
408
        new_tree = self.b.repository.revision_tree('rev-4')
385
 
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'],
 
409
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'], 
386
410
                            working_tree=self.wt)
387
411
        self.assertContainsRe(out, 'file1\t')
388
412
 
394
418
        self.wt.rename_one('file1', 'dir1/file1')
395
419
        old_tree = self.b.repository.revision_tree('rev-1')
396
420
        new_tree = self.b.repository.revision_tree('rev-4')
397
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'],
 
421
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'], 
398
422
                            working_tree=self.wt)
399
423
        self.assertContainsRe(out, 'file1\t')
400
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'],
 
424
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'], 
401
425
                            working_tree=self.wt)
402
426
        self.assertNotContainsRe(out, 'file1\t')
403
427
 
414
438
        tree.commit('one', rev_id='rev-1')
415
439
 
416
440
        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')
 
441
        diff = self.get_diff(tree.basis_tree(), tree)
 
442
        self.assertContainsRe(diff, "=== modified file 'file'\n")
 
443
        self.assertContainsRe(diff, '--- old/file\t')
 
444
        self.assertContainsRe(diff, '\\+\\+\\+ new/file\t')
 
445
        self.assertContainsRe(diff, '-contents\n'
 
446
                                    '\\+new contents\n')
423
447
 
424
448
    def test_modified_file_in_renamed_dir(self):
425
449
        """Test when a file is modified in a renamed directory."""
431
455
 
432
456
        tree.rename_one('dir', 'other')
433
457
        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")
 
458
        diff = self.get_diff(tree.basis_tree(), tree)
 
459
        self.assertContainsRe(diff, "=== renamed directory 'dir' => 'other'\n")
 
460
        self.assertContainsRe(diff, "=== modified file 'other/file'\n")
437
461
        # XXX: This is technically incorrect, because it used to be at another
438
462
        # 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')
 
463
        self.assertContainsRe(diff, '--- old/dir/file\t')
 
464
        self.assertContainsRe(diff, '\\+\\+\\+ new/other/file\t')
 
465
        self.assertContainsRe(diff, '-contents\n'
 
466
                                    '\\+new contents\n')
443
467
 
444
468
    def test_renamed_directory(self):
445
469
        """Test when only a directory is only renamed."""
450
474
        tree.commit('one', rev_id='rev-1')
451
475
 
452
476
        tree.rename_one('dir', 'newdir')
453
 
        d = self.get_diff(tree.basis_tree(), tree)
 
477
        diff = self.get_diff(tree.basis_tree(), tree)
454
478
        # Renaming a directory should be a single "you renamed this dir" even
455
479
        # when there are files inside.
456
 
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
 
480
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
457
481
 
458
482
    def test_renamed_file(self):
459
483
        """Test when a file is only renamed."""
463
487
        tree.commit('one', rev_id='rev-1')
464
488
 
465
489
        tree.rename_one('file', 'newname')
466
 
        d = self.get_diff(tree.basis_tree(), tree)
467
 
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
 
490
        diff = self.get_diff(tree.basis_tree(), tree)
 
491
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
468
492
        # We shouldn't have a --- or +++ line, because there is no content
469
493
        # change
470
 
        self.assertNotContainsRe(d, '---')
 
494
        self.assertNotContainsRe(diff, '---')
471
495
 
472
496
    def test_renamed_and_modified_file(self):
473
497
        """Test when a file is only renamed."""
478
502
 
479
503
        tree.rename_one('file', 'newname')
480
504
        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')
487
 
 
488
 
 
489
 
    def test_internal_diff_exec_property(self):
490
 
        tree = self.make_branch_and_tree('tree')
491
 
 
492
 
        tt = transform.TreeTransform(tree)
493
 
        tt.new_file('a', tt.root, 'contents\n', 'a-id', True)
494
 
        tt.new_file('b', tt.root, 'contents\n', 'b-id', False)
495
 
        tt.new_file('c', tt.root, 'contents\n', 'c-id', True)
496
 
        tt.new_file('d', tt.root, 'contents\n', 'd-id', False)
497
 
        tt.new_file('e', tt.root, 'contents\n', 'control-e-id', True)
498
 
        tt.new_file('f', tt.root, 'contents\n', 'control-f-id', False)
499
 
        tt.apply()
500
 
        tree.commit('one', rev_id='rev-1')
501
 
 
502
 
        tt = transform.TreeTransform(tree)
503
 
        tt.set_executability(False, tt.trans_id_file_id('a-id'))
504
 
        tt.set_executability(True, tt.trans_id_file_id('b-id'))
505
 
        tt.set_executability(False, tt.trans_id_file_id('c-id'))
506
 
        tt.set_executability(True, tt.trans_id_file_id('d-id'))
507
 
        tt.apply()
508
 
        tree.rename_one('c', 'new-c')
509
 
        tree.rename_one('d', 'new-d')
510
 
 
511
 
        d = self.get_diff(tree.basis_tree(), tree)
512
 
 
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'")
523
 
 
 
505
        diff = self.get_diff(tree.basis_tree(), tree)
 
506
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
 
507
        self.assertContainsRe(diff, '--- old/file\t')
 
508
        self.assertContainsRe(diff, '\\+\\+\\+ new/newname\t')
 
509
        self.assertContainsRe(diff, '-contents\n'
 
510
                                    '\\+new contents\n')
524
511
 
525
512
    def test_binary_unicode_filenames(self):
526
513
        """Test that contents of files are *not* encoded in UTF-8 when there
527
514
        is a binary file in the diff.
528
515
        """
529
516
        # See https://bugs.launchpad.net/bugs/110092.
530
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
517
        self.requireFeature(UnicodeFilename)
531
518
 
532
519
        # This bug isn't triggered with cStringIO.
533
520
        from StringIO import StringIO
541
528
        tree.add([alpha], ['file-id'])
542
529
        tree.add([omega], ['file-id-2'])
543
530
        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,))
 
531
        show_diff_trees(tree.basis_tree(), tree, diff_content)
 
532
        diff = diff_content.getvalue()
 
533
        self.assertContainsRe(diff, r"=== added file '%s'" % alpha_utf8)
 
534
        self.assertContainsRe(
 
535
            diff, "Binary files a/%s.*and b/%s.* differ\n" % (alpha_utf8, alpha_utf8))
 
536
        self.assertContainsRe(diff, r"=== added file '%s'" % omega_utf8)
 
537
        self.assertContainsRe(diff, r"--- a/%s" % (omega_utf8,))
 
538
        self.assertContainsRe(diff, r"\+\+\+ b/%s" % (omega_utf8,))
552
539
 
553
540
    def test_unicode_filename(self):
554
541
        """Test when the filename are unicode."""
555
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
542
        self.requireFeature(UnicodeFilename)
556
543
 
557
544
        alpha, omega = u'\u03b1', u'\u03c9'
558
545
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
573
560
        tree.add(['add_'+alpha], ['file-id'])
574
561
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
575
562
 
576
 
        d = self.get_diff(tree.basis_tree(), tree)
577
 
        self.assertContainsRe(d,
 
563
        diff = self.get_diff(tree.basis_tree(), tree)
 
564
        self.assertContainsRe(diff,
578
565
                "=== 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):
 
566
        self.assertContainsRe(diff, "=== added file 'add_%s'"%autf8)
 
567
        self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
 
568
        self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
 
569
 
 
570
 
 
571
class DiffWasIs(DiffPath):
585
572
 
586
573
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
587
574
        self.to_file.write('was: ')
591
578
        pass
592
579
 
593
580
 
594
 
class TestDiffTree(tests.TestCaseWithTransport):
 
581
class TestDiffTree(TestCaseWithTransport):
595
582
 
596
583
    def setUp(self):
597
 
        super(TestDiffTree, self).setUp()
 
584
        TestCaseWithTransport.setUp(self)
598
585
        self.old_tree = self.make_branch_and_tree('old-tree')
599
586
        self.old_tree.lock_write()
600
587
        self.addCleanup(self.old_tree.unlock)
601
588
        self.new_tree = self.make_branch_and_tree('new-tree')
602
589
        self.new_tree.lock_write()
603
590
        self.addCleanup(self.new_tree.unlock)
604
 
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
 
591
        self.differ = DiffTree(self.old_tree, self.new_tree, StringIO())
605
592
 
606
593
    def test_diff_text(self):
607
594
        self.build_tree_contents([('old-tree/olddir/',),
612
599
                                  ('new-tree/newdir/newfile', 'new\n')])
613
600
        self.new_tree.add('newdir')
614
601
        self.new_tree.add('newdir/newfile', 'file-id')
615
 
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
 
602
        differ = DiffText(self.old_tree, self.new_tree, StringIO())
616
603
        differ.diff_text('file-id', None, 'old label', 'new label')
617
604
        self.assertEqual(
618
605
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
647
634
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
648
635
 
649
636
    def test_diff_symlink(self):
650
 
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
637
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
651
638
        differ.diff_symlink('old target', None)
652
639
        self.assertEqual("=== target was 'old target'\n",
653
640
                         differ.to_file.getvalue())
654
641
 
655
 
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
642
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
656
643
        differ.diff_symlink(None, 'new target')
657
644
        self.assertEqual("=== target is 'new target'\n",
658
645
                         differ.to_file.getvalue())
659
646
 
660
 
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
647
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
661
648
        differ.diff_symlink('old target', 'new target')
662
649
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
663
650
                         differ.to_file.getvalue())
693
680
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
694
681
             ' \@\@\n-old\n\n')
695
682
        self.assertContainsRe(self.differ.to_file.getvalue(),
696
 
                              "=== target is u'new'\n")
 
683
                              "=== target is 'new'\n")
697
684
 
698
685
    def test_diff_directory(self):
699
686
        self.build_tree(['new-tree/new-dir/'])
713
700
 
714
701
    def test_register_diff(self):
715
702
        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)
 
703
        old_diff_factories = DiffTree.diff_factories
 
704
        DiffTree.diff_factories=old_diff_factories[:]
 
705
        DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
719
706
        try:
720
 
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
 
707
            differ = DiffTree(self.old_tree, self.new_tree, StringIO())
721
708
        finally:
722
 
            diff.DiffTree.diff_factories = old_diff_factories
 
709
            DiffTree.diff_factories = old_diff_factories
723
710
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
724
711
        self.assertNotContainsRe(
725
712
            differ.to_file.getvalue(),
730
717
 
731
718
    def test_extra_factories(self):
732
719
        self.create_old_new()
733
 
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
734
 
                               extra_factories=[DiffWasIs.from_diff_tree])
 
720
        differ = DiffTree(self.old_tree, self.new_tree, StringIO(),
 
721
                            extra_factories=[DiffWasIs.from_diff_tree])
735
722
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
736
723
        self.assertNotContainsRe(
737
724
            differ.to_file.getvalue(),
750
737
            '.*a-file(.|\n)*b-file')
751
738
 
752
739
 
753
 
class TestPatienceDiffLib(tests.TestCase):
 
740
class TestPatienceDiffLib(TestCase):
754
741
 
755
742
    def setUp(self):
756
743
        super(TestPatienceDiffLib, self).setUp()
757
 
        self._unique_lcs = _patiencediff_py.unique_lcs_py
758
 
        self._recurse_matches = _patiencediff_py.recurse_matches_py
 
744
        self._unique_lcs = bzrlib._patiencediff_py.unique_lcs_py
 
745
        self._recurse_matches = bzrlib._patiencediff_py.recurse_matches_py
759
746
        self._PatienceSequenceMatcher = \
760
 
            _patiencediff_py.PatienceSequenceMatcher_py
761
 
 
762
 
    def test_diff_unicode_string(self):
763
 
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
764
 
        b = ''.join([unichr(i) for i in range(4300, 4800, 2)])
765
 
        sm = self._PatienceSequenceMatcher(None, a, b)
766
 
        mb = sm.get_matching_blocks()
767
 
        self.assertEquals(35, len(mb))
 
747
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
768
748
 
769
749
    def test_unique_lcs(self):
770
750
        unique_lcs = self._unique_lcs
776
756
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
777
757
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
778
758
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
779
 
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1),
 
759
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1), 
780
760
                                                         (3,3), (4,4)])
781
761
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
782
762
 
797
777
        test_one('abcdbce', 'afbcgdbce', [(0,0), (1, 2), (2, 3), (3, 5),
798
778
                                          (4, 6), (5, 7), (6, 8)])
799
779
 
800
 
        # recurse_matches doesn't match non-unique
 
780
        # recurse_matches doesn't match non-unique 
801
781
        # lines surrounded by bogus text.
802
782
        # The update has been done in patiencediff.SequenceMatcher instead
803
783
 
940
920
                 ('delete', 1,2, 1,1),
941
921
                 ('equal',  2,3, 1,2),
942
922
                ])
943
 
        chk_ops('aBccDe', 'abccde',
 
923
        chk_ops('aBccDe', 'abccde', 
944
924
                [('equal',   0,1, 0,1),
945
925
                 ('replace', 1,5, 1,5),
946
926
                 ('equal',   5,6, 5,6),
947
927
                ])
948
 
        chk_ops('aBcDec', 'abcdec',
 
928
        chk_ops('aBcDec', 'abcdec', 
949
929
                [('equal',   0,1, 0,1),
950
930
                 ('replace', 1,2, 1,2),
951
931
                 ('equal',   2,3, 2,3),
952
932
                 ('replace', 3,4, 3,4),
953
933
                 ('equal',   4,6, 4,6),
954
934
                ])
955
 
        chk_ops('aBcdEcdFg', 'abcdecdfg',
 
935
        chk_ops('aBcdEcdFg', 'abcdecdfg', 
956
936
                [('equal',   0,1, 0,1),
957
937
                 ('replace', 1,8, 1,8),
958
938
                 ('equal',   8,9, 8,9)
959
939
                ])
960
 
        chk_ops('aBcdEeXcdFg', 'abcdecdfg',
 
940
        chk_ops('aBcdEeXcdFg', 'abcdecdfg', 
961
941
                [('equal',   0,1, 0,1),
962
942
                 ('replace', 1,2, 1,2),
963
943
                 ('equal',   2,4, 2,4),
1023
1003
    """
1024
1004
    gnxrf_netf = ['svyr*']
1025
1005
    gnxrf_bcgvbaf = ['ab-erphefr']
1026
 
 
 
1006
  
1027
1007
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
1028
1008
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
1029
1009
        vs vf_dhvrg():
1037
1017
'''.splitlines(True), '''\
1038
1018
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
1039
1019
 
1040
 
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl
 
1020
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl 
1041
1021
    nqq gurz.
1042
1022
    """
1043
1023
    gnxrf_netf = ['svyr*']
1070
1050
                 'how are you today?\n']
1071
1051
        txt_b = ['hello there\n',
1072
1052
                 'how are you today?\n']
1073
 
        unified_diff = patiencediff.unified_diff
 
1053
        unified_diff = bzrlib.patiencediff.unified_diff
1074
1054
        psm = self._PatienceSequenceMatcher
1075
 
        self.assertEquals(['--- \n',
1076
 
                           '+++ \n',
 
1055
        self.assertEquals([ '---  \n',
 
1056
                           '+++  \n',
1077
1057
                           '@@ -1,3 +1,2 @@\n',
1078
1058
                           ' hello there\n',
1079
1059
                           '-world\n',
1084
1064
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1085
1065
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1086
1066
        # This is the result with LongestCommonSubstring matching
1087
 
        self.assertEquals(['--- \n',
1088
 
                           '+++ \n',
 
1067
        self.assertEquals(['---  \n',
 
1068
                           '+++  \n',
1089
1069
                           '@@ -1,6 +1,11 @@\n',
1090
1070
                           ' a\n',
1091
1071
                           ' b\n',
1100
1080
                           ' f\n']
1101
1081
                          , list(unified_diff(txt_a, txt_b)))
1102
1082
        # And the patience diff
1103
 
        self.assertEquals(['--- \n',
1104
 
                           '+++ \n',
 
1083
        self.assertEquals(['---  \n',
 
1084
                           '+++  \n',
1105
1085
                           '@@ -4,6 +4,11 @@\n',
1106
1086
                           ' d\n',
1107
1087
                           ' e\n',
1118
1098
                          , list(unified_diff(txt_a, txt_b,
1119
1099
                                 sequencematcher=psm)))
1120
1100
 
1121
 
    def test_patience_unified_diff_with_dates(self):
1122
 
        txt_a = ['hello there\n',
1123
 
                 'world\n',
1124
 
                 'how are you today?\n']
1125
 
        txt_b = ['hello there\n',
1126
 
                 'how are you today?\n']
1127
 
        unified_diff = patiencediff.unified_diff
1128
 
        psm = self._PatienceSequenceMatcher
1129
 
        self.assertEquals(['--- a\t2008-08-08\n',
1130
 
                           '+++ b\t2008-09-09\n',
1131
 
                           '@@ -1,3 +1,2 @@\n',
1132
 
                           ' hello there\n',
1133
 
                           '-world\n',
1134
 
                           ' how are you today?\n'
1135
 
                          ]
1136
 
                          , list(unified_diff(txt_a, txt_b,
1137
 
                                 fromfile='a', tofile='b',
1138
 
                                 fromfiledate='2008-08-08',
1139
 
                                 tofiledate='2008-09-09',
1140
 
                                 sequencematcher=psm)))
1141
 
 
1142
1101
 
1143
1102
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1144
1103
 
1145
 
    _test_needs_features = [compiled_patiencediff_feature]
 
1104
    _test_needs_features = [CompiledPatienceDiffFeature]
1146
1105
 
1147
1106
    def setUp(self):
1148
1107
        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
 
1108
        import bzrlib._patiencediff_c
 
1109
        self._unique_lcs = bzrlib._patiencediff_c.unique_lcs_c
 
1110
        self._recurse_matches = bzrlib._patiencediff_c.recurse_matches_c
1152
1111
        self._PatienceSequenceMatcher = \
1153
 
            _patiencediff_c.PatienceSequenceMatcher_c
 
1112
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
1154
1113
 
1155
1114
    def test_unhashable(self):
1156
1115
        """We should get a proper exception here."""
1166
1125
                                         None, ['valid'], ['valid', []])
1167
1126
 
1168
1127
 
1169
 
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
 
1128
class TestPatienceDiffLibFiles(TestCaseInTempDir):
1170
1129
 
1171
1130
    def setUp(self):
1172
1131
        super(TestPatienceDiffLibFiles, self).setUp()
1173
1132
        self._PatienceSequenceMatcher = \
1174
 
            _patiencediff_py.PatienceSequenceMatcher_py
 
1133
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
1175
1134
 
1176
1135
    def test_patience_unified_diff_files(self):
1177
1136
        txt_a = ['hello there\n',
1182
1141
        open('a1', 'wb').writelines(txt_a)
1183
1142
        open('b1', 'wb').writelines(txt_b)
1184
1143
 
1185
 
        unified_diff_files = patiencediff.unified_diff_files
 
1144
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
1186
1145
        psm = self._PatienceSequenceMatcher
1187
 
        self.assertEquals(['--- a1\n',
1188
 
                           '+++ b1\n',
 
1146
        self.assertEquals(['--- a1 \n',
 
1147
                           '+++ b1 \n',
1189
1148
                           '@@ -1,3 +1,2 @@\n',
1190
1149
                           ' hello there\n',
1191
1150
                           '-world\n',
1200
1159
        open('b2', 'wb').writelines(txt_b)
1201
1160
 
1202
1161
        # This is the result with LongestCommonSubstring matching
1203
 
        self.assertEquals(['--- a2\n',
1204
 
                           '+++ b2\n',
 
1162
        self.assertEquals(['--- a2 \n',
 
1163
                           '+++ b2 \n',
1205
1164
                           '@@ -1,6 +1,11 @@\n',
1206
1165
                           ' a\n',
1207
1166
                           ' b\n',
1217
1176
                          , list(unified_diff_files('a2', 'b2')))
1218
1177
 
1219
1178
        # And the patience diff
1220
 
        self.assertEquals(['--- a2\n',
1221
 
                           '+++ b2\n',
 
1179
        self.assertEquals(['--- a2 \n',
 
1180
                           '+++ b2 \n',
1222
1181
                           '@@ -4,6 +4,11 @@\n',
1223
1182
                           ' d\n',
1224
1183
                           ' e\n',
1238
1197
 
1239
1198
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1240
1199
 
1241
 
    _test_needs_features = [compiled_patiencediff_feature]
 
1200
    _test_needs_features = [CompiledPatienceDiffFeature]
1242
1201
 
1243
1202
    def setUp(self):
1244
1203
        super(TestPatienceDiffLibFiles_c, self).setUp()
1245
 
        from bzrlib import _patiencediff_c
 
1204
        import bzrlib._patiencediff_c
1246
1205
        self._PatienceSequenceMatcher = \
1247
 
            _patiencediff_c.PatienceSequenceMatcher_c
1248
 
 
1249
 
 
1250
 
class TestUsingCompiledIfAvailable(tests.TestCase):
 
1206
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
 
1207
 
 
1208
 
 
1209
class TestUsingCompiledIfAvailable(TestCase):
1251
1210
 
1252
1211
    def test_PatienceSequenceMatcher(self):
1253
 
        if compiled_patiencediff_feature.available():
 
1212
        if CompiledPatienceDiffFeature.available():
1254
1213
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1255
1214
            self.assertIs(PatienceSequenceMatcher_c,
1256
 
                          patiencediff.PatienceSequenceMatcher)
 
1215
                          bzrlib.patiencediff.PatienceSequenceMatcher)
1257
1216
        else:
1258
1217
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1259
1218
            self.assertIs(PatienceSequenceMatcher_py,
1260
 
                          patiencediff.PatienceSequenceMatcher)
 
1219
                          bzrlib.patiencediff.PatienceSequenceMatcher)
1261
1220
 
1262
1221
    def test_unique_lcs(self):
1263
 
        if compiled_patiencediff_feature.available():
 
1222
        if CompiledPatienceDiffFeature.available():
1264
1223
            from bzrlib._patiencediff_c import unique_lcs_c
1265
1224
            self.assertIs(unique_lcs_c,
1266
 
                          patiencediff.unique_lcs)
 
1225
                          bzrlib.patiencediff.unique_lcs)
1267
1226
        else:
1268
1227
            from bzrlib._patiencediff_py import unique_lcs_py
1269
1228
            self.assertIs(unique_lcs_py,
1270
 
                          patiencediff.unique_lcs)
 
1229
                          bzrlib.patiencediff.unique_lcs)
1271
1230
 
1272
1231
    def test_recurse_matches(self):
1273
 
        if compiled_patiencediff_feature.available():
 
1232
        if CompiledPatienceDiffFeature.available():
1274
1233
            from bzrlib._patiencediff_c import recurse_matches_c
1275
1234
            self.assertIs(recurse_matches_c,
1276
 
                          patiencediff.recurse_matches)
 
1235
                          bzrlib.patiencediff.recurse_matches)
1277
1236
        else:
1278
1237
            from bzrlib._patiencediff_py import recurse_matches_py
1279
1238
            self.assertIs(recurse_matches_py,
1280
 
                          patiencediff.recurse_matches)
1281
 
 
1282
 
 
1283
 
class TestDiffFromTool(tests.TestCaseWithTransport):
 
1239
                          bzrlib.patiencediff.recurse_matches)
 
1240
 
 
1241
 
 
1242
class TestDiffFromTool(TestCaseWithTransport):
1284
1243
 
1285
1244
    def test_from_string(self):
1286
 
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
 
1245
        diff_obj = DiffFromTool.from_string('diff', None, None, None)
1287
1246
        self.addCleanup(diff_obj.finish)
1288
 
        self.assertEqual(['diff', '@old_path', '@new_path'],
 
1247
        self.assertEqual(['diff', '%(old_path)s', '%(new_path)s'],
1289
1248
            diff_obj.command_template)
1290
 
 
1291
 
    def test_from_string_u5(self):
1292
 
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
1293
 
                                                 None, None, None)
1294
 
        self.addCleanup(diff_obj.finish)
1295
 
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
 
1249
        diff_obj = DiffFromTool.from_string('diff -u\\ 5', None, None, None)
 
1250
        self.assertEqual(['diff', '-u 5', '%(old_path)s', '%(new_path)s'],
1296
1251
                         diff_obj.command_template)
1297
1252
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1298
1253
                         diff_obj._get_command('old-path', 'new-path'))
1299
1254
 
1300
 
    def test_from_string_path_with_backslashes(self):
1301
 
        self.requireFeature(test_win32utils.BackslashDirSeparatorFeature)
1302
 
        tool = 'C:\\Tools\\Diff.exe'
1303
 
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
1304
 
        self.addCleanup(diff_obj.finish)
1305
 
        self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
1306
 
                         diff_obj.command_template)
1307
 
        self.assertEqual(['C:\\Tools\\Diff.exe', 'old-path', 'new-path'],
1308
 
                         diff_obj._get_command('old-path', 'new-path'))
1309
 
 
1310
1255
    def test_execute(self):
1311
1256
        output = StringIO()
1312
 
        diff_obj = diff.DiffFromTool(['python', '-c',
1313
 
                                      'print "@old_path @new_path"'],
1314
 
                                     None, None, output)
 
1257
        diff_obj = DiffFromTool(['python', '-c',
 
1258
                                 'print "%(old_path)s %(new_path)s"'],
 
1259
                                None, None, output)
1315
1260
        self.addCleanup(diff_obj.finish)
1316
1261
        diff_obj._execute('old', 'new')
1317
1262
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1318
1263
 
1319
1264
    def test_excute_missing(self):
1320
 
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1321
 
                                     None, None, None)
 
1265
        diff_obj = DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
 
1266
                                None, None, None)
1322
1267
        self.addCleanup(diff_obj.finish)
1323
 
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
1324
 
                              'old', 'new')
 
1268
        e = self.assertRaises(ExecutableMissing, diff_obj._execute, 'old',
 
1269
                              'new')
1325
1270
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1326
1271
                         ' on this machine', str(e))
1327
1272
 
1328
 
    def test_prepare_files_creates_paths_readable_by_windows_tool(self):
1329
 
        self.requireFeature(AttribFeature)
1330
 
        output = StringIO()
1331
 
        tree = self.make_branch_and_tree('tree')
1332
 
        self.build_tree_contents([('tree/file', 'content')])
1333
 
        tree.add('file', 'file-id')
1334
 
        tree.commit('old tree')
1335
 
        tree.lock_read()
1336
 
        self.addCleanup(tree.unlock)
1337
 
        basis_tree = tree.basis_tree()
1338
 
        basis_tree.lock_read()
1339
 
        self.addCleanup(basis_tree.unlock)
1340
 
        diff_obj = diff.DiffFromTool(['python', '-c',
1341
 
                                      'print "@old_path @new_path"'],
1342
 
                                     basis_tree, tree, output)
1343
 
        diff_obj._prepare_files('file-id', 'file', 'file')
1344
 
        # The old content should be readonly
1345
 
        self.assertReadableByAttrib(diff_obj._root, 'old\\file',
1346
 
                                    r'R.*old\\file$')
1347
 
        # The new content should use the tree object, not a 'new' file anymore
1348
 
        self.assertEndsWith(tree.basedir, 'work/tree')
1349
 
        self.assertReadableByAttrib(tree.basedir, 'file', r'work\\tree\\file$')
1350
 
 
1351
 
    def assertReadableByAttrib(self, cwd, relpath, regex):
1352
 
        proc = subprocess.Popen(['attrib', relpath],
1353
 
                                stdout=subprocess.PIPE,
1354
 
                                cwd=cwd)
1355
 
        (result, err) = proc.communicate()
1356
 
        self.assertContainsRe(result.replace('\r\n', '\n'), regex)
1357
 
 
1358
1273
    def test_prepare_files(self):
1359
1274
        output = StringIO()
1360
1275
        tree = self.make_branch_and_tree('tree')
1361
1276
        self.build_tree_contents([('tree/oldname', 'oldcontent')])
1362
 
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
1363
1277
        tree.add('oldname', 'file-id')
1364
 
        tree.add('oldname2', 'file2-id')
1365
 
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
1366
 
        tree.commit('old tree', timestamp=315532800)
 
1278
        tree.commit('old tree', timestamp=0)
1367
1279
        tree.rename_one('oldname', 'newname')
1368
 
        tree.rename_one('oldname2', 'newname2')
1369
1280
        self.build_tree_contents([('tree/newname', 'newcontent')])
1370
 
        self.build_tree_contents([('tree/newname2', 'newcontent2')])
1371
1281
        old_tree = tree.basis_tree()
1372
1282
        old_tree.lock_read()
1373
1283
        self.addCleanup(old_tree.unlock)
1374
1284
        tree.lock_read()
1375
1285
        self.addCleanup(tree.unlock)
1376
 
        diff_obj = diff.DiffFromTool(['python', '-c',
1377
 
                                      'print "@old_path @new_path"'],
1378
 
                                     old_tree, tree, output)
 
1286
        diff_obj = DiffFromTool(['python', '-c',
 
1287
                                 'print "%(old_path)s %(new_path)s"'],
 
1288
                                old_tree, tree, output)
1379
1289
        self.addCleanup(diff_obj.finish)
1380
1290
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1381
1291
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1382
1292
                                                     'newname')
1383
1293
        self.assertContainsRe(old_path, 'old/oldname$')
1384
 
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
1385
 
        self.assertContainsRe(new_path, 'tree/newname$')
 
1294
        self.assertEqual(0, os.stat(old_path).st_mtime)
 
1295
        self.assertContainsRe(new_path, 'new/newname$')
1386
1296
        self.assertFileEqual('oldcontent', old_path)
1387
1297
        self.assertFileEqual('newcontent', new_path)
1388
 
        if osutils.host_os_dereferences_symlinks():
 
1298
        if osutils.has_symlinks():
1389
1299
            self.assertTrue(os.path.samefile('tree/newname', new_path))
1390
1300
        # make sure we can create files with the same parent directories
1391
 
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1392
 
 
1393
 
 
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)
1402
 
 
1403
 
    def test_basic(self):
1404
 
        tree = self.make_branch_and_tree('tree')
1405
 
        (old_tree, new_tree,
1406
 
         old_branch, new_branch,
1407
 
         specific_files, extra_trees) = self.call_gtabtd(
1408
 
             ['tree'], None, None, None)
1409
 
 
1410
 
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1411
 
        self.assertEqual(_mod_revision.NULL_REVISION,
1412
 
                         old_tree.get_revision_id())
1413
 
        self.assertEqual(tree.basedir, new_tree.basedir)
1414
 
        self.assertEqual(tree.branch.base, old_branch.base)
1415
 
        self.assertEqual(tree.branch.base, new_branch.base)
1416
 
        self.assertIs(None, specific_files)
1417
 
        self.assertIs(None, extra_trees)
1418
 
 
1419
 
    def test_with_rev_specs(self):
1420
 
        tree = self.make_branch_and_tree('tree')
1421
 
        self.build_tree_contents([('tree/file', 'oldcontent')])
1422
 
        tree.add('file', 'file-id')
1423
 
        tree.commit('old tree', timestamp=0, rev_id="old-id")
1424
 
        self.build_tree_contents([('tree/file', 'newcontent')])
1425
 
        tree.commit('new tree', timestamp=0, rev_id="new-id")
1426
 
 
1427
 
        revisions = [revisionspec.RevisionSpec.from_string('1'),
1428
 
                     revisionspec.RevisionSpec.from_string('2')]
1429
 
        (old_tree, new_tree,
1430
 
         old_branch, new_branch,
1431
 
         specific_files, extra_trees) = self.call_gtabtd(
1432
 
            ['tree'], revisions, None, None)
1433
 
 
1434
 
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1435
 
        self.assertEqual("old-id", old_tree.get_revision_id())
1436
 
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
1437
 
        self.assertEqual("new-id", new_tree.get_revision_id())
1438
 
        self.assertEqual(tree.branch.base, old_branch.base)
1439
 
        self.assertEqual(tree.branch.base, new_branch.base)
1440
 
        self.assertIs(None, specific_files)
1441
 
        self.assertEqual(tree.basedir, extra_trees[0].basedir)
1442
 
 
1443
 
 
1444
 
class TestGetTreesAndBranchesToDiff(TestGetTreesAndBranchesToDiffLocked):
1445
 
    """Apply the tests for get_trees_and_branches_to_diff_locked to the
1446
 
    deprecated get_trees_and_branches_to_diff function.
1447
 
    """
1448
 
 
1449
 
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
1450
 
        return self.applyDeprecated(
1451
 
            deprecated_in((2, 2, 0)), diff.get_trees_and_branches_to_diff,
1452
 
            path_list, revision_specs, old_url, new_url)
1453
 
 
 
1301
        diff_obj._prepare_files('file-id', 'oldname2', 'newname2')