18
18
from cStringIO import StringIO
21
from tempfile import TemporaryFile
20
from bzrlib.diff import internal_diff, show_diff_trees
21
from bzrlib.errors import BinaryFile
23
from bzrlib.diff import internal_diff, external_diff, show_diff_trees
24
from bzrlib.errors import BinaryFile, NoDiff
22
25
import bzrlib.patiencediff
23
from bzrlib.tests import TestCase, TestCaseWithTransport, TestCaseInTempDir
24
from bzrlib.tests import TestCase, TestCaseInTempDir
26
from bzrlib.tests import (TestCase, TestCaseWithTransport,
27
TestCaseInTempDir, TestSkipped)
27
30
def udiff_lines(old, new, allow_binary=False):
31
34
return output.readlines()
37
def external_udiff_lines(old, new, use_stringio=False):
39
# StringIO has no fileno, so it tests a different codepath
42
output = TemporaryFile()
44
external_diff('old', old, 'new', new, output, diff_opts=['-u'])
46
raise TestSkipped('external "diff" not present to test')
48
lines = output.readlines()
34
53
class TestDiff(TestCase):
36
55
def test_add_nl(self):
78
97
udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
79
98
udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
100
def test_external_diff(self):
101
lines = external_udiff_lines(['boo\n'], ['goo\n'])
102
self.check_patch(lines)
103
self.assertEqual('\n', lines[-1])
105
def test_external_diff_no_fileno(self):
106
# Make sure that we can handle not having a fileno, even
107
# if the diff is large
108
lines = external_udiff_lines(['boo\n']*10000,
111
self.check_patch(lines)
113
def test_external_diff_binary_lang_c(self):
114
orig_lang = os.environ.get('LANG')
116
os.environ['LANG'] = 'C'
117
lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
118
# Older versions of diffutils say "Binary files", newer
119
# versions just say "Files".
120
self.assertContainsRe(lines[0],
121
'(Binary f|F)iles old and new differ\n')
122
self.assertEquals(lines[1:], ['\n'])
124
if orig_lang is None:
125
del os.environ['LANG']
127
os.environ['LANG'] = orig_lang
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']
134
os.environ['PATH'] = ''
135
self.assertRaises(NoDiff, external_diff,
136
'old', ['boo\n'], 'new', ['goo\n'],
137
StringIO(), diff_opts=['-u'])
139
os.environ['PATH'] = orig_path
81
141
def test_internal_diff_default(self):
82
142
# Default internal diff encoding is utf8
83
143
output = StringIO()
135
195
'internal_diff should return bytestrings')
198
class TestDiffFiles(TestCaseInTempDir):
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'])
205
cmd = ['diff', '-u', '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)
138
217
class TestDiffDates(TestCaseWithTransport):
175
254
# set the date stamps for files in the working tree to known values
176
255
os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
178
def get_diff(self, tree1, tree2):
257
def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
179
258
output = StringIO()
180
show_diff_trees(tree1, tree2, output,
181
old_label='old/', new_label='new/')
259
if working_tree is not None:
260
extra_trees = (working_tree,)
263
show_diff_trees(tree1, tree2, output, specific_files=specific_files,
264
extra_trees=extra_trees, old_label='old/',
182
266
return output.getvalue()
184
268
def test_diff_rev_tree_working_tree(self):
332
def test_show_diff_specified(self):
333
"""A working tree filename can be used to identify a file"""
334
self.wt.rename_one('file1', 'file1b')
335
old_tree = self.b.repository.revision_tree('rev-1')
336
new_tree = self.b.repository.revision_tree('rev-4')
337
out = self.get_diff(old_tree, new_tree, specific_files=['file1b'],
338
working_tree=self.wt)
339
self.assertContainsRe(out, 'file1\t')
341
def test_recursive_diff(self):
342
"""Children of directories are matched"""
345
self.wt.add(['dir1', 'dir2'])
346
self.wt.rename_one('file1', 'dir1/file1')
347
old_tree = self.b.repository.revision_tree('rev-1')
348
new_tree = self.b.repository.revision_tree('rev-4')
349
out = self.get_diff(old_tree, new_tree, specific_files=['dir1'],
350
working_tree=self.wt)
351
self.assertContainsRe(out, 'file1\t')
352
out = self.get_diff(old_tree, new_tree, specific_files=['dir2'],
353
working_tree=self.wt)
354
self.assertNotContainsRe(out, 'file1\t')
249
357
class TestPatienceDiffLib(TestCase):