1
# Copyright (C) 2005, 2006 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
"""Black-box tests for bzr diff.
25
from bzrlib import workingtree
26
from bzrlib.branch import Branch
27
from bzrlib.tests import TestSkipped
28
from bzrlib.tests.blackbox import ExternalBase
31
def subst_dates(string):
32
"""Replace date strings with constant values."""
33
return re.sub(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-\+]\d{4}',
34
'YYYY-MM-DD HH:MM:SS +ZZZZ', string)
37
class DiffBase(ExternalBase):
38
"""Base class with common setup method"""
40
def make_example_branch(self):
41
tree = self.make_branch_and_tree('.')
42
self.build_tree_contents([
44
('goodbye', 'baz\n')])
52
class TestDiff(DiffBase):
55
tree = self.make_example_branch()
56
self.build_tree_contents([('hello', 'hello world!')])
57
tree.commit(message='fixing hello')
58
output = self.run_bzr('diff -r 2..3', retcode=1)[0]
59
self.assert_('\n+hello world!' in output)
60
output = self.run_bzr('diff -r last:3..last:1',
62
self.assert_('\n+baz' in output)
63
self.build_tree(['moo'])
68
def test_diff_prefix(self):
69
"""diff --prefix appends to filenames in output"""
70
self.make_example_branch()
71
self.build_tree_contents([('hello', 'hello world!\n')])
72
out, err = self.run_bzr('diff --prefix old/:new/', retcode=1)
73
self.assertEquals(err, '')
74
self.assertEqualDiff(subst_dates(out), '''\
75
=== modified file 'hello'
76
--- old/hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
77
+++ new/hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
84
def test_diff_illegal_prefix_value(self):
85
# There was an error in error reporting for this option
86
out, err = self.run_bzr('diff --prefix old/', retcode=3)
87
self.assertContainsRe(err,
88
'--prefix expects two values separated by a colon')
90
def test_diff_p1(self):
91
"""diff -p1 produces lkml-style diffs"""
92
self.make_example_branch()
93
self.build_tree_contents([('hello', 'hello world!\n')])
94
out, err = self.run_bzr('diff -p1', retcode=1)
95
self.assertEquals(err, '')
96
self.assertEqualDiff(subst_dates(out), '''\
97
=== modified file 'hello'
98
--- old/hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
99
+++ new/hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
106
def test_diff_p0(self):
107
"""diff -p0 produces diffs with no prefix"""
108
self.make_example_branch()
109
self.build_tree_contents([('hello', 'hello world!\n')])
110
out, err = self.run_bzr('diff -p0', retcode=1)
111
self.assertEquals(err, '')
112
self.assertEqualDiff(subst_dates(out), '''\
113
=== modified file 'hello'
114
--- hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
115
+++ hello\tYYYY-MM-DD HH:MM:SS +ZZZZ
122
def test_diff_nonexistent(self):
123
# Get an error from a file that does not exist at all
125
self.make_example_branch()
126
out, err = self.run_bzr('diff does-not-exist', retcode=3)
127
self.assertContainsRe(err, 'not versioned.*does-not-exist')
129
def test_diff_illegal_revision_specifiers(self):
130
out, err = self.run_bzr('diff -r 1..23..123', retcode=3)
131
self.assertContainsRe(err, 'one or two revision specifiers')
133
def test_diff_unversioned(self):
134
# Get an error when diffing a non-versioned file.
136
self.make_example_branch()
137
self.build_tree(['unversioned-file'])
138
out, err = self.run_bzr('diff unversioned-file', retcode=3)
139
self.assertContainsRe(err, 'not versioned.*unversioned-file')
141
# TODO: What should diff say for a file deleted in working tree?
143
def example_branches(self):
144
branch1_tree = self.make_branch_and_tree('branch1')
145
self.build_tree(['branch1/file'], line_endings='binary')
146
branch1_tree.add('file')
147
branch1_tree.commit(message='add file')
148
branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
149
self.build_tree_contents([('branch2/file', 'new content\n')])
150
branch2_tree.commit(message='update file')
151
return branch1_tree, branch2_tree
153
def test_diff_branches(self):
154
self.example_branches()
155
# should open branch1 and diff against branch2,
156
out, err = self.run_bzr('diff -r branch:branch2 branch1',
158
self.assertEquals('', err)
159
self.assertEquals("=== modified file 'file'\n"
160
"--- file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
161
"+++ file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
164
"+contents of branch1/file\n"
165
"\n", subst_dates(out))
166
out, err = self.run_bzr('diff branch2 branch1',
168
self.assertEquals('', err)
169
self.assertEqualDiff("=== modified file 'file'\n"
170
"--- file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
171
"+++ file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
174
"+contents of branch1/file\n"
175
"\n", subst_dates(out))
177
def test_diff_revno_branches(self):
178
self.example_branches()
179
branch2_tree = workingtree.WorkingTree.open_containing('branch2')[0]
180
self.build_tree_contents([('branch2/file', 'even newer content')])
181
branch2_tree.commit(message='update file once more')
183
out, err = self.run_bzr('diff -r revno:1:branch2..revno:1:branch1',
185
self.assertEquals('', err)
186
self.assertEquals('', out)
187
out, err = self.run_bzr('diff -r revno:2:branch2..revno:1:branch1',
189
self.assertEquals('', err)
190
self.assertEqualDiff("=== modified file 'file'\n"
191
"--- file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
192
"+++ file\tYYYY-MM-DD HH:MM:SS +ZZZZ\n"
195
"+contents of branch1/file\n"
196
"\n", subst_dates(out))
198
def example_branch2(self):
199
branch1_tree = self.make_branch_and_tree('branch1')
200
self.build_tree_contents([('branch1/file1', 'original line\n')])
201
branch1_tree.add('file1')
202
branch1_tree.commit(message='first commit')
203
self.build_tree_contents([('branch1/file1', 'repo line\n')])
204
branch1_tree.commit(message='second commit')
207
def test_diff_to_working_tree(self):
208
self.example_branch2()
209
self.build_tree_contents([('branch1/file1', 'new line')])
210
output = self.run_bzr('diff -r 1.. branch1', retcode=1)
211
self.assertContainsRe(output[0], '\n\\-original line\n\\+new line\n')
213
def test_diff_across_rename(self):
214
"""The working tree path should always be considered for diffing"""
215
tree = self.make_example_branch()
216
self.run_bzr('diff -r 0..1 hello', retcode=1)
217
tree.rename_one('hello', 'hello1')
218
self.run_bzr('diff hello1', retcode=1)
219
self.run_bzr('diff -r 0..1 hello1', retcode=1)
222
class TestCheckoutDiff(TestDiff):
224
def make_example_branch(self):
225
tree = super(TestCheckoutDiff, self).make_example_branch()
226
tree = tree.branch.create_checkout('checkout')
230
def example_branch2(self):
231
tree = super(TestCheckoutDiff, self).example_branch2()
232
os.mkdir('checkouts')
233
tree = tree.branch.create_checkout('checkouts/branch1')
234
os.chdir('checkouts')
237
def example_branches(self):
238
branch1_tree, branch2_tree = super(TestCheckoutDiff, self).example_branches()
239
os.mkdir('checkouts')
240
branch1_tree = branch1_tree.branch.create_checkout('checkouts/branch1')
241
branch2_tree = branch2_tree.branch.create_checkout('checkouts/branch2')
242
os.chdir('checkouts')
243
return branch1_tree, branch2_tree
246
class TestDiffLabels(DiffBase):
248
def test_diff_label_removed(self):
249
tree = super(TestDiffLabels, self).make_example_branch()
250
tree.remove('hello', keep_files=False)
251
diff = self.run_bzr('diff', retcode=1)
252
self.assertTrue("=== removed file 'hello'" in diff[0])
254
def test_diff_label_added(self):
255
tree = super(TestDiffLabels, self).make_example_branch()
256
self.build_tree_contents([('barbar', 'barbar')])
258
diff = self.run_bzr('diff', retcode=1)
259
self.assertTrue("=== added file 'barbar'" in diff[0])
261
def test_diff_label_modified(self):
262
super(TestDiffLabels, self).make_example_branch()
263
self.build_tree_contents([('hello', 'barbar')])
264
diff = self.run_bzr('diff', retcode=1)
265
self.assertTrue("=== modified file 'hello'" in diff[0])
267
def test_diff_label_renamed(self):
268
tree = super(TestDiffLabels, self).make_example_branch()
269
tree.rename_one('hello', 'gruezi')
270
diff = self.run_bzr('diff', retcode=1)
271
self.assertTrue("=== renamed file 'hello' => 'gruezi'" in diff[0])
274
class TestExternalDiff(DiffBase):
276
def test_external_diff(self):
277
"""Test that we can spawn an external diff process"""
278
# We have to use run_bzr_subprocess, because we need to
279
# test writing directly to stdout, (there was a bug in
280
# subprocess.py that we had to workaround).
281
# However, if 'diff' may not be available
282
self.make_example_branch()
283
orig_progress = os.environ.get('BZR_PROGRESS_BAR')
285
os.environ['BZR_PROGRESS_BAR'] = 'none'
286
out, err = self.run_bzr_subprocess('diff -r 1 --diff-options -ub',
287
universal_newlines=True,
290
if orig_progress is None:
291
del os.environ['BZR_PROGRESS_BAR']
293
os.environ['BZR_PROGRESS_BAR'] = orig_progress
295
if 'Diff is not installed on this machine' in err:
296
raise TestSkipped("No external 'diff' is available")
297
self.assertEqual('', err)
298
# We have to skip the stuff in the middle, because it depends
300
self.assertStartsWith(out, "=== added file 'goodbye'\n"
301
"--- goodbye\t1970-01-01 00:00:00 +0000\n"
303
self.assertEndsWith(out, "\n@@ -0,0 +1 @@\n"
307
class TestDiffOutput(DiffBase):
309
def test_diff_output(self):
310
# check that output doesn't mangle line-endings
311
self.make_example_branch()
312
self.build_tree_contents([('hello', 'hello world!\n')])
313
output = self.run_bzr_subprocess('diff', retcode=1)[0]
314
self.assert_('\n+hello world!\n' in output)