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
17
"""Tests of status command.
19
Most of these depend on the particular formatting used.
20
As such they really are blackbox tests even though some of the
21
tests are not using self.capture. If we add tests for the programmatic
22
interface later, they will be non blackbox tests.
25
from cStringIO import StringIO
27
from os import mkdir, chdir, rmdir, unlink
29
from tempfile import TemporaryFile
31
from bzrlib import bzrdir, errors
33
from bzrlib.builtins import merge
34
from bzrlib.osutils import pathjoin
35
from bzrlib.revisionspec import RevisionSpec
36
from bzrlib.status import show_tree_status
37
from bzrlib.tests import TestCaseWithTransport, TestSkipped
38
from bzrlib.workingtree import WorkingTree
41
class BranchStatus(TestCaseWithTransport):
43
def assertStatus(self, expected_lines, working_tree,
44
revision=None, short=False):
45
"""Run status in working_tree and look for output.
47
:param expected_lines: The lines to look for.
48
:param working_tree: The tree to run status in.
50
output_string = self.status_string(working_tree, revision, short)
51
self.assertEqual(expected_lines, output_string.splitlines(True))
53
def status_string(self, wt, revision=None, short=False):
54
# use a real file rather than StringIO because it doesn't handle
56
tof = codecs.getwriter('utf-8')(TemporaryFile())
57
show_tree_status(wt, to_file=tof, revision=revision, short=short)
59
return tof.read().decode('utf-8')
61
def test_branch_status(self):
62
"""Test basic branch status"""
63
wt = self.make_branch_and_tree('.')
65
# status with no commits or files - it must
66
# work and show no output. We do this with no
67
# commits to be sure that it's not going to fail
69
self.assertStatus([], wt)
71
self.build_tree(['hello.c', 'bye.c'])
84
# add a commit to allow showing pending merges.
85
wt.commit('create a parent to allow testing merge output')
87
wt.add_parent_tree_id('pending@pending-0-0')
93
' pending@pending-0-0\n',
99
'P pending@pending-0-0\n',
103
def test_branch_status_revisions(self):
104
"""Tests branch status with revisions"""
105
wt = self.make_branch_and_tree('.')
107
self.build_tree(['hello.c', 'bye.c'])
110
wt.commit('Test message')
112
revs = [RevisionSpec.from_string('0')]
121
self.build_tree(['more.c'])
123
wt.commit('Another test message')
125
revs.append(RevisionSpec.from_string('1'))
134
def test_pending(self):
135
"""Pending merges display works, including Unicode"""
137
wt = self.make_branch_and_tree('branch')
139
wt.commit("Empty commit 1")
140
b_2_dir = b.bzrdir.sprout('./copy')
141
b_2 = b_2_dir.open_branch()
142
wt2 = b_2_dir.open_workingtree()
143
wt.commit(u"\N{TIBETAN DIGIT TWO} Empty commit 2")
144
merge(["./branch", -1], [None, None], this_dir = './copy')
145
message = self.status_string(wt2)
146
self.assertStartsWith(message, "pending merges:\n")
147
self.assertEndsWith(message, "Empty commit 2\n")
149
# must be long to make sure we see elipsis at the end
150
wt.commit("Empty commit 3 " +
151
"blah blah blah blah " * 100)
152
merge(["./branch", -1], [None, None], this_dir = './copy')
153
message = self.status_string(wt2)
154
self.assertStartsWith(message, "pending merges:\n")
155
self.assert_("Empty commit 3" in message)
156
self.assertEndsWith(message, "...\n")
158
def test_tree_status_ignores(self):
159
"""Tests branch status with ignores"""
160
wt = self.make_branch_and_tree('.')
161
self.run_bzr('ignore', '*~')
162
wt.commit('commit .bzrignore')
163
self.build_tree(['foo.c', 'foo.c~'])
174
def test_tree_status_specific_files(self):
175
"""Tests branch status with given specific files"""
176
wt = self.make_branch_and_tree('.')
179
self.build_tree(['directory/','directory/hello.c', 'bye.c','test.c','dir2/'])
188
' directory/hello.c\n'
195
'? directory/hello.c\n'
200
self.assertRaises(errors.PathsDoNotExist,
202
wt, specific_files=['bye.c','test.c','absent.c'],
206
show_tree_status(wt, specific_files=['directory'], to_file=tof)
208
self.assertEquals(tof.readlines(),
210
' directory/hello.c\n'
213
show_tree_status(wt, specific_files=['directory'], to_file=tof,
216
self.assertEquals(tof.readlines(), ['? directory/hello.c\n'])
219
show_tree_status(wt, specific_files=['dir2'], to_file=tof)
221
self.assertEquals(tof.readlines(),
226
show_tree_status(wt, specific_files=['dir2'], to_file=tof, short=True)
228
self.assertEquals(tof.readlines(), ['? dir2/\n'])
230
def test_status_nonexistent_file(self):
231
# files that don't exist in either the basis tree or working tree
232
# should give an error
233
wt = self.make_branch_and_tree('.')
234
out, err = self.run_bzr('status', 'does-not-exist', retcode=3)
235
self.assertContainsRe(err, r'do not exist.*does-not-exist')
237
def test_status_out_of_date(self):
238
"""Simulate status of out-of-date tree after remote push"""
239
tree = self.make_branch_and_tree('.')
240
self.build_tree_contents([('a', 'foo\n')])
244
tree.commit('add test file')
245
# simulate what happens after a remote push
246
tree.set_last_revision("0")
247
out, err = self.run_bzr('status')
248
self.assertEqual("working tree is out of date, run 'bzr update'\n",
254
class CheckoutStatus(BranchStatus):
257
super(CheckoutStatus, self).setUp()
261
def make_branch_and_tree(self, relpath):
262
source = self.make_branch(pathjoin('..', relpath))
263
checkout = bzrdir.BzrDirMetaFormat1().initialize(relpath)
264
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
265
return checkout.create_workingtree()
268
class TestStatus(TestCaseWithTransport):
270
def test_status_plain(self):
273
self.build_tree(['hello.txt'])
274
result = self.run_bzr("status")[0]
275
self.assertContainsRe(result, "unknown:\n hello.txt\n")
277
self.run_bzr("add", "hello.txt")
278
result = self.run_bzr("status")[0]
279
self.assertContainsRe(result, "added:\n hello.txt\n")
281
self.run_bzr("commit", "-m", "added")
282
result = self.run_bzr("status", "-r", "0..1")[0]
283
self.assertContainsRe(result, "added:\n hello.txt\n")
285
self.build_tree(['world.txt'])
286
result = self.run_bzr("status", "-r", "0")[0]
287
self.assertContainsRe(result, "added:\n hello.txt\n" \
288
"unknown:\n world.txt\n")
289
result2 = self.run_bzr("status", "-r", "0..")[0]
290
self.assertEquals(result2, result)
292
def test_status_short(self):
295
self.build_tree(['hello.txt'])
296
result = self.run_bzr("status","--short")[0]
297
self.assertContainsRe(result, "[?] hello.txt\n")
299
self.run_bzr("add", "hello.txt")
300
result = self.run_bzr("status","--short")[0]
301
self.assertContainsRe(result, "[+]N hello.txt\n")
303
self.run_bzr("commit", "-m", "added")
304
result = self.run_bzr("status", "--short", "-r", "0..1")[0]
305
self.assertContainsRe(result, "[+]N hello.txt\n")
307
self.build_tree(['world.txt'])
308
result = self.run_bzr("status", "--short", "-r", "0")[0]
309
self.assertContainsRe(result, "[+]N hello.txt\n" \
311
result2 = self.run_bzr("status", "--short", "-r", "0..")[0]
312
self.assertEquals(result2, result)
314
def test_status_versioned(self):
317
self.build_tree(['hello.txt'])
318
result = self.run_bzr("status", "--versioned")[0]
319
self.assertNotContainsRe(result, "unknown:\n hello.txt\n")
321
self.run_bzr("add", "hello.txt")
322
result = self.run_bzr("status", "--versioned")[0]
323
self.assertContainsRe(result, "added:\n hello.txt\n")
325
self.run_bzr("commit", "-m", "added")
326
result = self.run_bzr("status", "--versioned", "-r", "0..1")[0]
327
self.assertContainsRe(result, "added:\n hello.txt\n")
329
self.build_tree(['world.txt'])
330
result = self.run_bzr("status", "--versioned", "-r", "0")[0]
331
self.assertContainsRe(result, "added:\n hello.txt\n")
332
self.assertNotContainsRe(result, "unknown:\n world.txt\n")
333
result2 = self.run_bzr("status", "--versioned", "-r", "0..")[0]
334
self.assertEquals(result2, result)
336
def assertStatusContains(self, pattern):
337
"""Run status, and assert it contains the given pattern"""
338
result = self.run_bzr("status", "--short")[0]
339
self.assertContainsRe(result, pattern)
341
def test_kind_change_short(self):
342
tree = self.make_branch_and_tree('.')
343
self.build_tree(['file'])
345
tree.commit('added file')
347
self.build_tree(['file/'])
348
self.assertStatusContains('K file => file/')
349
tree.rename_one('file', 'directory')
350
self.assertStatusContains('RK file => directory/')
352
self.assertStatusContains('RD file => directory')
355
class TestStatusEncodings(TestCaseWithTransport):
358
TestCaseWithTransport.setUp(self)
359
self.user_encoding = bzrlib.user_encoding
360
self.stdout = sys.stdout
363
bzrlib.user_encoding = self.user_encoding
364
sys.stdout = self.stdout
365
TestCaseWithTransport.tearDown(self)
367
def make_uncommitted_tree(self):
368
"""Build a branch with uncommitted unicode named changes in the cwd."""
369
working_tree = self.make_branch_and_tree(u'.')
370
filename = u'hell\u00d8'
372
self.build_tree_contents([(filename, 'contents of hello')])
373
except UnicodeEncodeError:
374
raise TestSkipped("can't build unicode working tree in "
375
"filesystem encoding %s" % sys.getfilesystemencoding())
376
working_tree.add(filename)
379
def test_stdout_ascii(self):
380
sys.stdout = StringIO()
381
bzrlib.user_encoding = 'ascii'
382
working_tree = self.make_uncommitted_tree()
383
stdout, stderr = self.run_bzr("status")
385
self.assertEquals(stdout, """\
390
def test_stdout_latin1(self):
391
sys.stdout = StringIO()
392
bzrlib.user_encoding = 'latin-1'
393
working_tree = self.make_uncommitted_tree()
394
stdout, stderr = self.run_bzr('status')
396
self.assertEquals(stdout, u"""\
399
""".encode('latin-1'))