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")
248
# before run another commands we should unlock tree
250
out, err = self.run_bzr('status')
251
self.assertEqual("working tree is out of date, run 'bzr update'\n",
255
class CheckoutStatus(BranchStatus):
258
super(CheckoutStatus, self).setUp()
262
def make_branch_and_tree(self, relpath):
263
source = self.make_branch(pathjoin('..', relpath))
264
checkout = bzrdir.BzrDirMetaFormat1().initialize(relpath)
265
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
266
return checkout.create_workingtree()
269
class TestStatus(TestCaseWithTransport):
271
def test_status_plain(self):
274
self.build_tree(['hello.txt'])
275
result = self.run_bzr("status")[0]
276
self.assertContainsRe(result, "unknown:\n hello.txt\n")
278
self.run_bzr("add hello.txt")
279
result = self.run_bzr("status")[0]
280
self.assertContainsRe(result, "added:\n hello.txt\n")
282
self.run_bzr("commit -m added")
283
result = self.run_bzr("status -r 0..1")[0]
284
self.assertContainsRe(result, "added:\n hello.txt\n")
286
self.build_tree(['world.txt'])
287
result = self.run_bzr("status -r 0")[0]
288
self.assertContainsRe(result, "added:\n hello.txt\n" \
289
"unknown:\n world.txt\n")
290
result2 = self.run_bzr("status -r 0..")[0]
291
self.assertEquals(result2, result)
293
def test_status_short(self):
296
self.build_tree(['hello.txt'])
297
result = self.run_bzr("status --short")[0]
298
self.assertContainsRe(result, "[?] hello.txt\n")
300
self.run_bzr("add hello.txt")
301
result = self.run_bzr("status --short")[0]
302
self.assertContainsRe(result, "[+]N hello.txt\n")
304
self.run_bzr("commit -m added")
305
result = self.run_bzr("status --short -r 0..1")[0]
306
self.assertContainsRe(result, "[+]N hello.txt\n")
308
self.build_tree(['world.txt'])
309
result = self.run_bzr("status --short -r 0")[0]
310
self.assertContainsRe(result, "[+]N hello.txt\n" \
312
result2 = self.run_bzr("status --short -r 0..")[0]
313
self.assertEquals(result2, result)
315
def test_status_versioned(self):
318
self.build_tree(['hello.txt'])
319
result = self.run_bzr("status --versioned")[0]
320
self.assertNotContainsRe(result, "unknown:\n hello.txt\n")
322
self.run_bzr("add hello.txt")
323
result = self.run_bzr("status --versioned")[0]
324
self.assertContainsRe(result, "added:\n hello.txt\n")
326
self.run_bzr("commit -m added")
327
result = self.run_bzr("status --versioned -r 0..1")[0]
328
self.assertContainsRe(result, "added:\n hello.txt\n")
330
self.build_tree(['world.txt'])
331
result = self.run_bzr("status --versioned -r 0")[0]
332
self.assertContainsRe(result, "added:\n hello.txt\n")
333
self.assertNotContainsRe(result, "unknown:\n world.txt\n")
334
result2 = self.run_bzr("status --versioned -r 0..")[0]
335
self.assertEquals(result2, result)
337
def assertStatusContains(self, pattern):
338
"""Run status, and assert it contains the given pattern"""
339
result = self.run_bzr("status --short")[0]
340
self.assertContainsRe(result, pattern)
342
def test_kind_change_short(self):
343
tree = self.make_branch_and_tree('.')
344
self.build_tree(['file'])
346
tree.commit('added file')
348
self.build_tree(['file/'])
349
self.assertStatusContains('K file => file/')
350
tree.rename_one('file', 'directory')
351
self.assertStatusContains('RK file => directory/')
353
self.assertStatusContains('RD file => directory')
356
class TestStatusEncodings(TestCaseWithTransport):
359
TestCaseWithTransport.setUp(self)
360
self.user_encoding = bzrlib.user_encoding
361
self.stdout = sys.stdout
364
bzrlib.user_encoding = self.user_encoding
365
sys.stdout = self.stdout
366
TestCaseWithTransport.tearDown(self)
368
def make_uncommitted_tree(self):
369
"""Build a branch with uncommitted unicode named changes in the cwd."""
370
working_tree = self.make_branch_and_tree(u'.')
371
filename = u'hell\u00d8'
373
self.build_tree_contents([(filename, 'contents of hello')])
374
except UnicodeEncodeError:
375
raise TestSkipped("can't build unicode working tree in "
376
"filesystem encoding %s" % sys.getfilesystemencoding())
377
working_tree.add(filename)
380
def test_stdout_ascii(self):
381
sys.stdout = StringIO()
382
bzrlib.user_encoding = 'ascii'
383
working_tree = self.make_uncommitted_tree()
384
stdout, stderr = self.run_bzr("status")
386
self.assertEquals(stdout, """\
391
def test_stdout_latin1(self):
392
sys.stdout = StringIO()
393
bzrlib.user_encoding = 'latin-1'
394
working_tree = self.make_uncommitted_tree()
395
stdout, stderr = self.run_bzr('status')
397
self.assertEquals(stdout, u"""\
400
""".encode('latin-1'))