~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Wouter van Heyst
  • Date: 2006-06-07 16:05:27 UTC
  • mto: This revision was merged to the branch mainline in revision 1752.
  • Revision ID: larstiq@larstiq.dyndns.org-20060607160527-2b3649154d0e2e84
more code cleanup

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical Development 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
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
import os
18
18
from cStringIO import StringIO
19
 
import errno
20
 
import subprocess
21
 
from tempfile import TemporaryFile
22
19
 
23
 
from bzrlib.diff import internal_diff, external_diff, show_diff_trees
24
 
from bzrlib.errors import BinaryFile, NoDiff
25
 
import bzrlib.osutils as osutils
 
20
from bzrlib.diff import internal_diff, show_diff_trees
 
21
from bzrlib.errors import BinaryFile
26
22
import bzrlib.patiencediff
27
 
from bzrlib.tests import (TestCase, TestCaseWithTransport,
28
 
                          TestCaseInTempDir, TestSkipped)
 
23
from bzrlib.tests import TestCase, TestCaseWithTransport, TestCaseInTempDir
 
24
from bzrlib.tests import TestCase, TestCaseInTempDir
29
25
 
30
26
 
31
27
def udiff_lines(old, new, allow_binary=False):
35
31
    return output.readlines()
36
32
 
37
33
 
38
 
def external_udiff_lines(old, new, use_stringio=False):
39
 
    if use_stringio:
40
 
        # StringIO has no fileno, so it tests a different codepath
41
 
        output = StringIO()
42
 
    else:
43
 
        output = TemporaryFile()
44
 
    try:
45
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
46
 
    except NoDiff:
47
 
        raise TestSkipped('external "diff" not present to test')
48
 
    output.seek(0, 0)
49
 
    lines = output.readlines()
50
 
    output.close()
51
 
    return lines
52
 
 
53
 
 
54
34
class TestDiff(TestCase):
55
35
 
56
36
    def test_add_nl(self):
98
78
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
99
79
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
100
80
 
101
 
    def test_external_diff(self):
102
 
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
103
 
        self.check_patch(lines)
104
 
        self.assertEqual('\n', lines[-1])
105
 
 
106
 
    def test_external_diff_no_fileno(self):
107
 
        # Make sure that we can handle not having a fileno, even
108
 
        # if the diff is large
109
 
        lines = external_udiff_lines(['boo\n']*10000,
110
 
                                     ['goo\n']*10000,
111
 
                                     use_stringio=True)
112
 
        self.check_patch(lines)
113
 
 
114
 
    def test_external_diff_binary_lang_c(self):
115
 
        old_env = {}
116
 
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
117
 
            old_env[lang] = osutils.set_or_unset_env(lang, 'C')
118
 
        try:
119
 
            lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
120
 
            # Older versions of diffutils say "Binary files", newer
121
 
            # versions just say "Files".
122
 
            self.assertContainsRe(lines[0],
123
 
                                  '(Binary f|F)iles old and new differ\n')
124
 
            self.assertEquals(lines[1:], ['\n'])
125
 
        finally:
126
 
            for lang, old_val in old_env.iteritems():
127
 
                osutils.set_or_unset_env(lang, old_val)
128
 
 
129
 
    def test_no_external_diff(self):
130
 
        """Check that NoDiff is raised when diff is not available"""
131
 
        # Use os.environ['PATH'] to make sure no 'diff' command is available
132
 
        orig_path = os.environ['PATH']
133
 
        try:
134
 
            os.environ['PATH'] = ''
135
 
            self.assertRaises(NoDiff, external_diff,
136
 
                              'old', ['boo\n'], 'new', ['goo\n'],
137
 
                              StringIO(), diff_opts=['-u'])
138
 
        finally:
139
 
            os.environ['PATH'] = orig_path
140
 
        
141
81
    def test_internal_diff_default(self):
142
82
        # Default internal diff encoding is utf8
143
83
        output = StringIO()
195
135
            'internal_diff should return bytestrings')
196
136
 
197
137
 
198
 
class TestDiffFiles(TestCaseInTempDir):
199
 
 
200
 
    def test_external_diff_binary(self):
201
 
        """The output when using external diff should use diff's i18n error"""
202
 
        # Make sure external_diff doesn't fail in the current LANG
203
 
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
204
 
 
205
 
        cmd = ['diff', '-u', '--binary', 'old', 'new']
206
 
        open('old', 'wb').write('\x00foobar\n')
207
 
        open('new', 'wb').write('foo\x00bar\n')
208
 
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
209
 
                                     stdin=subprocess.PIPE)
210
 
        out, err = pipe.communicate()
211
 
        # Diff returns '2' on Binary files.
212
 
        self.assertEqual(2, pipe.returncode)
213
 
        # We should output whatever diff tells us, plus a trailing newline
214
 
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
215
 
 
216
 
 
217
 
class TestShowDiffTreesHelper(TestCaseWithTransport):
218
 
    """Has a helper for running show_diff_trees"""
219
 
 
220
 
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
221
 
        output = StringIO()
222
 
        if working_tree is not None:
223
 
            extra_trees = (working_tree,)
224
 
        else:
225
 
            extra_trees = ()
226
 
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
227
 
                        extra_trees=extra_trees, old_label='old/',
228
 
                        new_label='new/')
229
 
        return output.getvalue()
230
 
 
231
 
 
232
 
class TestDiffDates(TestShowDiffTreesHelper):
 
138
class TestDiffDates(TestCaseWithTransport):
233
139
 
234
140
    def setUp(self):
235
141
        super(TestDiffDates, self).setUp()
269
175
        # set the date stamps for files in the working tree to known values
270
176
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
271
177
 
 
178
    def get_diff(self, tree1, tree2):
 
179
        output = StringIO()
 
180
        show_diff_trees(tree1, tree2, output,
 
181
                        old_label='old/', new_label='new/')
 
182
        return output.getvalue()
 
183
 
272
184
    def test_diff_rev_tree_working_tree(self):
273
185
        output = self.get_diff(self.wt.basis_tree(), self.wt)
274
186
        # note that the date for old/file1 is from rev 2 rather than from
333
245
 
334
246
''')
335
247
 
336
 
    def test_show_diff_specified(self):
337
 
        """A working tree filename can be used to identify a file"""
338
 
        self.wt.rename_one('file1', 'file1b')
339
 
        old_tree = self.b.repository.revision_tree('rev-1')
340
 
        new_tree = self.b.repository.revision_tree('rev-4')
341
 
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'], 
342
 
                            working_tree=self.wt)
343
 
        self.assertContainsRe(out, 'file1\t')
344
 
 
345
 
    def test_recursive_diff(self):
346
 
        """Children of directories are matched"""
347
 
        os.mkdir('dir1')
348
 
        os.mkdir('dir2')
349
 
        self.wt.add(['dir1', 'dir2'])
350
 
        self.wt.rename_one('file1', 'dir1/file1')
351
 
        old_tree = self.b.repository.revision_tree('rev-1')
352
 
        new_tree = self.b.repository.revision_tree('rev-4')
353
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'], 
354
 
                            working_tree=self.wt)
355
 
        self.assertContainsRe(out, 'file1\t')
356
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'], 
357
 
                            working_tree=self.wt)
358
 
        self.assertNotContainsRe(out, 'file1\t')
359
 
 
360
 
 
361
 
 
362
 
class TestShowDiffTrees(TestShowDiffTreesHelper):
363
 
    """Direct tests for show_diff_trees"""
364
 
 
365
 
    def test_modified_file(self):
366
 
        """Test when a file is modified."""
367
 
        tree = self.make_branch_and_tree('tree')
368
 
        self.build_tree_contents([('tree/file', 'contents\n')])
369
 
        tree.add(['file'], ['file-id'])
370
 
        tree.commit('one', rev_id='rev-1')
371
 
 
372
 
        self.build_tree_contents([('tree/file', 'new contents\n')])
373
 
        diff = self.get_diff(tree.basis_tree(), tree)
374
 
        self.assertContainsRe(diff, "=== modified file 'file'\n")
375
 
        self.assertContainsRe(diff, '--- old/file\t')
376
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/file\t')
377
 
        self.assertContainsRe(diff, '-contents\n'
378
 
                                    '\\+new contents\n')
379
 
 
380
 
    def test_modified_file_in_renamed_dir(self):
381
 
        """Test when a file is modified in a renamed directory."""
382
 
        tree = self.make_branch_and_tree('tree')
383
 
        self.build_tree(['tree/dir/'])
384
 
        self.build_tree_contents([('tree/dir/file', 'contents\n')])
385
 
        tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
386
 
        tree.commit('one', rev_id='rev-1')
387
 
 
388
 
        tree.rename_one('dir', 'other')
389
 
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
390
 
        diff = self.get_diff(tree.basis_tree(), tree)
391
 
        self.assertContainsRe(diff, "=== renamed directory 'dir' => 'other'\n")
392
 
        self.assertContainsRe(diff, "=== modified file 'other/file'\n")
393
 
        # XXX: This is technically incorrect, because it used to be at another
394
 
        # location. What to do?
395
 
        self.assertContainsRe(diff, '--- old/dir/file\t')
396
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/other/file\t')
397
 
        self.assertContainsRe(diff, '-contents\n'
398
 
                                    '\\+new contents\n')
399
 
 
400
 
    def test_renamed_directory(self):
401
 
        """Test when only a directory is only renamed."""
402
 
        tree = self.make_branch_and_tree('tree')
403
 
        self.build_tree(['tree/dir/'])
404
 
        self.build_tree_contents([('tree/dir/file', 'contents\n')])
405
 
        tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
406
 
        tree.commit('one', rev_id='rev-1')
407
 
 
408
 
        tree.rename_one('dir', 'newdir')
409
 
        diff = self.get_diff(tree.basis_tree(), tree)
410
 
        # Renaming a directory should be a single "you renamed this dir" even
411
 
        # when there are files inside.
412
 
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
413
 
 
414
 
    def test_renamed_file(self):
415
 
        """Test when a file is only renamed."""
416
 
        tree = self.make_branch_and_tree('tree')
417
 
        self.build_tree_contents([('tree/file', 'contents\n')])
418
 
        tree.add(['file'], ['file-id'])
419
 
        tree.commit('one', rev_id='rev-1')
420
 
 
421
 
        tree.rename_one('file', 'newname')
422
 
        diff = self.get_diff(tree.basis_tree(), tree)
423
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
424
 
        # We shouldn't have a --- or +++ line, because there is no content
425
 
        # change
426
 
        self.assertNotContainsRe(diff, '---')
427
 
 
428
 
    def test_renamed_and_modified_file(self):
429
 
        """Test when a file is only renamed."""
430
 
        tree = self.make_branch_and_tree('tree')
431
 
        self.build_tree_contents([('tree/file', 'contents\n')])
432
 
        tree.add(['file'], ['file-id'])
433
 
        tree.commit('one', rev_id='rev-1')
434
 
 
435
 
        tree.rename_one('file', 'newname')
436
 
        self.build_tree_contents([('tree/newname', 'new contents\n')])
437
 
        diff = self.get_diff(tree.basis_tree(), tree)
438
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
439
 
        self.assertContainsRe(diff, '--- old/file\t')
440
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/newname\t')
441
 
        self.assertContainsRe(diff, '-contents\n'
442
 
                                    '\\+new contents\n')
443
 
 
444
248
 
445
249
class TestPatienceDiffLib(TestCase):
446
250