~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Andrew Bennetts
  • Date: 2009-12-18 08:22:42 UTC
  • mfrom: (4906 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4909.
  • Revision ID: andrew.bennetts@canonical.com-20091218082242-f7wy9tlk0yxvkkju
MergeĀ lp:bzr.

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