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
38
from bzrlib.osutils import pathjoin
39
from bzrlib.revisionspec import RevisionSpec
40
from bzrlib.status import show_tree_status
41
from bzrlib.tests import TestCaseWithTransport, TestSkipped
42
from bzrlib.workingtree import WorkingTree
45
class BranchStatus(TestCaseWithTransport):
47
def assertStatus(self, expected_lines, working_tree,
48
revision=None, short=False):
49
"""Run status in working_tree and look for output.
51
:param expected_lines: The lines to look for.
52
:param working_tree: The tree to run status in.
54
output_string = self.status_string(working_tree, revision, short)
55
self.assertEqual(expected_lines, output_string.splitlines(True))
57
def status_string(self, wt, revision=None, short=False):
58
# use a real file rather than StringIO because it doesn't handle
60
tof = codecs.getwriter('utf-8')(TemporaryFile())
61
show_tree_status(wt, to_file=tof, revision=revision, short=short)
63
return tof.read().decode('utf-8')
65
def test_branch_status(self):
66
"""Test basic branch status"""
67
wt = self.make_branch_and_tree('.')
69
# status with no commits or files - it must
70
# work and show no output. We do this with no
71
# commits to be sure that it's not going to fail
73
self.assertStatus([], wt)
75
self.build_tree(['hello.c', 'bye.c'])
88
# add a commit to allow showing pending merges.
89
wt.commit('create a parent to allow testing merge output')
91
wt.add_parent_tree_id('pending@pending-0-0')
97
' pending@pending-0-0\n',
103
'P pending@pending-0-0\n',
107
def test_branch_status_revisions(self):
108
"""Tests branch status with revisions"""
109
wt = self.make_branch_and_tree('.')
111
self.build_tree(['hello.c', 'bye.c'])
114
wt.commit('Test message')
116
revs = [RevisionSpec.from_string('0')]
125
self.build_tree(['more.c'])
127
wt.commit('Another test message')
129
revs.append(RevisionSpec.from_string('1'))
138
def test_pending(self):
139
"""Pending merges display works, including Unicode"""
141
wt = self.make_branch_and_tree('branch')
143
wt.commit("Empty commit 1")
144
b_2_dir = b.bzrdir.sprout('./copy')
145
b_2 = b_2_dir.open_branch()
146
wt2 = b_2_dir.open_workingtree()
147
wt.commit(u"\N{TIBETAN DIGIT TWO} Empty commit 2")
148
wt2.merge_from_branch(wt.branch)
149
message = self.status_string(wt2)
150
self.assertStartsWith(message, "pending merges:\n")
151
self.assertEndsWith(message, "Empty commit 2\n")
153
# must be long to make sure we see elipsis at the end
154
wt.commit("Empty commit 3 " +
155
"blah blah blah blah " * 100)
156
wt2.merge_from_branch(wt.branch)
157
message = self.status_string(wt2)
158
self.assertStartsWith(message, "pending merges:\n")
159
self.assert_("Empty commit 3" in message)
160
self.assertEndsWith(message, "...\n")
162
def test_tree_status_ignores(self):
163
"""Tests branch status with ignores"""
164
wt = self.make_branch_and_tree('.')
165
self.run_bzr('ignore *~')
166
wt.commit('commit .bzrignore')
167
self.build_tree(['foo.c', 'foo.c~'])
178
def test_tree_status_specific_files(self):
179
"""Tests branch status with given specific files"""
180
wt = self.make_branch_and_tree('.')
183
self.build_tree(['directory/','directory/hello.c', 'bye.c','test.c','dir2/'])
192
' directory/hello.c\n'
199
'? directory/hello.c\n'
204
self.assertRaises(errors.PathsDoNotExist,
206
wt, specific_files=['bye.c','test.c','absent.c'],
210
show_tree_status(wt, specific_files=['directory'], to_file=tof)
212
self.assertEquals(tof.readlines(),
214
' directory/hello.c\n'
217
show_tree_status(wt, specific_files=['directory'], to_file=tof,
220
self.assertEquals(tof.readlines(), ['? directory/hello.c\n'])
223
show_tree_status(wt, specific_files=['dir2'], to_file=tof)
225
self.assertEquals(tof.readlines(),
230
show_tree_status(wt, specific_files=['dir2'], to_file=tof, short=True)
232
self.assertEquals(tof.readlines(), ['? dir2/\n'])
235
revs = [RevisionSpec.from_string('0'), RevisionSpec.from_string('1')]
236
show_tree_status(wt, specific_files=['test.c'], to_file=tof,
237
short=True, revision=revs)
239
self.assertEquals(tof.readlines(), ['+N test.c\n'])
241
def test_specific_files_conflicts(self):
242
tree = self.make_branch_and_tree('.')
243
self.build_tree(['dir2/'])
245
tree.commit('added dir2')
246
tree.set_conflicts(conflicts.ConflictList(
247
[conflicts.ContentsConflict('foo')]))
249
show_tree_status(tree, specific_files=['dir2'], to_file=tof)
250
self.assertEqualDiff('', tof.getvalue())
251
tree.set_conflicts(conflicts.ConflictList(
252
[conflicts.ContentsConflict('dir2')]))
254
show_tree_status(tree, specific_files=['dir2'], to_file=tof)
255
self.assertEqualDiff('conflicts:\n Contents conflict in dir2\n',
258
tree.set_conflicts(conflicts.ConflictList(
259
[conflicts.ContentsConflict('dir2/file1')]))
261
show_tree_status(tree, specific_files=['dir2'], to_file=tof)
262
self.assertEqualDiff('conflicts:\n Contents conflict in dir2/file1\n',
265
def test_status_nonexistent_file(self):
266
# files that don't exist in either the basis tree or working tree
267
# should give an error
268
wt = self.make_branch_and_tree('.')
269
out, err = self.run_bzr('status does-not-exist', retcode=3)
270
self.assertContainsRe(err, r'do not exist.*does-not-exist')
272
def test_status_out_of_date(self):
273
"""Simulate status of out-of-date tree after remote push"""
274
tree = self.make_branch_and_tree('.')
275
self.build_tree_contents([('a', 'foo\n')])
279
tree.commit('add test file')
280
# simulate what happens after a remote push
281
tree.set_last_revision("0")
283
# before run another commands we should unlock tree
285
out, err = self.run_bzr('status')
286
self.assertEqual("working tree is out of date, run 'bzr update'\n",
290
class CheckoutStatus(BranchStatus):
293
super(CheckoutStatus, self).setUp()
297
def make_branch_and_tree(self, relpath):
298
source = self.make_branch(pathjoin('..', relpath))
299
checkout = bzrdir.BzrDirMetaFormat1().initialize(relpath)
300
bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
301
return checkout.create_workingtree()
304
class TestStatus(TestCaseWithTransport):
306
def test_status_plain(self):
307
tree = self.make_branch_and_tree('.')
309
self.build_tree(['hello.txt'])
310
result = self.run_bzr("status")[0]
311
self.assertContainsRe(result, "unknown:\n hello.txt\n")
313
tree.add("hello.txt")
314
result = self.run_bzr("status")[0]
315
self.assertContainsRe(result, "added:\n hello.txt\n")
317
tree.commit(message="added")
318
result = self.run_bzr("status -r 0..1")[0]
319
self.assertContainsRe(result, "added:\n hello.txt\n")
321
result = self.run_bzr("status -c 1")[0]
322
self.assertContainsRe(result, "added:\n hello.txt\n")
324
self.build_tree(['world.txt'])
325
result = self.run_bzr("status -r 0")[0]
326
self.assertContainsRe(result, "added:\n hello.txt\n" \
327
"unknown:\n world.txt\n")
328
result2 = self.run_bzr("status -r 0..")[0]
329
self.assertEquals(result2, result)
331
def test_status_short(self):
332
tree = self.make_branch_and_tree('.')
334
self.build_tree(['hello.txt'])
335
result = self.run_bzr("status --short")[0]
336
self.assertContainsRe(result, "[?] hello.txt\n")
338
tree.add("hello.txt")
339
result = self.run_bzr("status --short")[0]
340
self.assertContainsRe(result, "[+]N hello.txt\n")
342
tree.commit(message="added")
343
result = self.run_bzr("status --short -r 0..1")[0]
344
self.assertContainsRe(result, "[+]N hello.txt\n")
346
self.build_tree(['world.txt'])
347
result = self.run_bzr("status --short -r 0")[0]
348
self.assertContainsRe(result, "[+]N hello.txt\n" \
350
result2 = self.run_bzr("status --short -r 0..")[0]
351
self.assertEquals(result2, result)
353
def test_status_versioned(self):
354
tree = self.make_branch_and_tree('.')
356
self.build_tree(['hello.txt'])
357
result = self.run_bzr("status --versioned")[0]
358
self.assertNotContainsRe(result, "unknown:\n hello.txt\n")
360
tree.add("hello.txt")
361
result = self.run_bzr("status --versioned")[0]
362
self.assertContainsRe(result, "added:\n hello.txt\n")
365
result = self.run_bzr("status --versioned -r 0..1")[0]
366
self.assertContainsRe(result, "added:\n hello.txt\n")
368
self.build_tree(['world.txt'])
369
result = self.run_bzr("status --versioned -r 0")[0]
370
self.assertContainsRe(result, "added:\n hello.txt\n")
371
self.assertNotContainsRe(result, "unknown:\n world.txt\n")
372
result2 = self.run_bzr("status --versioned -r 0..")[0]
373
self.assertEquals(result2, result)
375
def test_status_SV(self):
376
tree = self.make_branch_and_tree('.')
378
self.build_tree(['hello.txt'])
379
result = self.run_bzr("status -SV")[0]
380
self.assertNotContainsRe(result, "hello.txt")
382
tree.add("hello.txt")
383
result = self.run_bzr("status -SV")[0]
384
self.assertContainsRe(result, "[+]N hello.txt\n")
386
tree.commit(message="added")
387
result = self.run_bzr("status -SV -r 0..1")[0]
388
self.assertContainsRe(result, "[+]N hello.txt\n")
390
self.build_tree(['world.txt'])
391
result = self.run_bzr("status -SV -r 0")[0]
392
self.assertContainsRe(result, "[+]N hello.txt\n")
394
result2 = self.run_bzr("status -SV -r 0..")[0]
395
self.assertEquals(result2, result)
397
def assertStatusContains(self, pattern):
398
"""Run status, and assert it contains the given pattern"""
399
result = self.run_bzr("status --short")[0]
400
self.assertContainsRe(result, pattern)
402
def test_kind_change_short(self):
403
tree = self.make_branch_and_tree('.')
404
self.build_tree(['file'])
406
tree.commit('added file')
408
self.build_tree(['file/'])
409
self.assertStatusContains('K file => file/')
410
tree.rename_one('file', 'directory')
411
self.assertStatusContains('RK file => directory/')
413
self.assertStatusContains('RD file => directory')
415
def test_status_illegal_revision_specifiers(self):
416
out, err = self.run_bzr('status -r 1..23..123', retcode=3)
417
self.assertContainsRe(err, 'one or two revision specifiers')
420
class TestStatusEncodings(TestCaseWithTransport):
423
TestCaseWithTransport.setUp(self)
424
self.user_encoding = osutils._cached_user_encoding
425
self.stdout = sys.stdout
428
bzrlib.user_encoding = self.user_encoding
429
sys.stdout = self.stdout
430
TestCaseWithTransport.tearDown(self)
432
def make_uncommitted_tree(self):
433
"""Build a branch with uncommitted unicode named changes in the cwd."""
434
working_tree = self.make_branch_and_tree(u'.')
435
filename = u'hell\u00d8'
437
self.build_tree_contents([(filename, 'contents of hello')])
438
except UnicodeEncodeError:
439
raise TestSkipped("can't build unicode working tree in "
440
"filesystem encoding %s" % sys.getfilesystemencoding())
441
working_tree.add(filename)
444
def test_stdout_ascii(self):
445
sys.stdout = StringIO()
446
osutils._cached_user_encoding = 'ascii'
447
working_tree = self.make_uncommitted_tree()
448
stdout, stderr = self.run_bzr("status")
450
self.assertEquals(stdout, """\
455
def test_stdout_latin1(self):
456
sys.stdout = StringIO()
457
osutils._cached_user_encoding = 'latin-1'
458
working_tree = self.make_uncommitted_tree()
459
stdout, stderr = self.run_bzr('status')
461
self.assertEquals(stdout, u"""\
464
""".encode('latin-1'))