22
22
interface later, they will be non blackbox tests.
25
from cStringIO import StringIO
26
27
from os import mkdir, chdir, rmdir, unlink
29
from tempfile import TemporaryFile
34
from breezy.bzr import (
39
from ...osutils import pathjoin
40
from ...revisionspec import RevisionSpec
41
from ...sixish import (
46
from ...status import show_tree_status
47
from .. import TestCaseWithTransport, TestSkipped
48
from ...workingtree import WorkingTree
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
51
45
class BranchStatus(TestCaseWithTransport):
54
super(BranchStatus, self).setUp()
55
# As TestCase.setUp clears all hooks, we install this default
56
# post_status hook handler for the test.
57
status.hooks.install_named_hook('post_status',
58
status._show_shelve_summary,
61
def assertStatus(self, expected_lines, working_tree, specific_files=None,
62
revision=None, short=False, pending=True, verbose=False):
47
def assertStatus(self, expected_lines, working_tree,
48
revision=None, short=False, pending=True, verbose=False):
63
49
"""Run status in working_tree and look for output.
65
51
:param expected_lines: The lines to look for.
66
52
:param working_tree: The tree to run status in.
68
output_string = self.status_string(working_tree, specific_files, revision, short,
54
output_string = self.status_string(working_tree, revision, short,
70
56
self.assertEqual(expected_lines, output_string.splitlines(True))
72
def status_string(self, wt, specific_files=None, revision=None,
73
short=False, pending=True, verbose=False):
74
uio = self.make_utf8_encoded_stringio()
75
show_tree_status(wt, specific_files=specific_files, to_file=uio,
76
revision=revision, short=short, show_pending=pending,
78
return uio.getvalue().decode('utf-8')
58
def status_string(self, wt, revision=None, short=False, pending=True,
60
# use a real file rather than StringIO because it doesn't handle
62
tof = codecs.getwriter('utf-8')(TemporaryFile())
63
show_tree_status(wt, to_file=tof, revision=revision, short=short,
64
show_pending=pending, verbose=verbose)
66
return tof.read().decode('utf-8')
80
68
def test_branch_status(self):
81
69
"""Test basic branch status"""
90
78
self.build_tree(['hello.c', 'bye.c'])
91
79
self.assertStatus([
97
85
self.assertStatus([
103
91
# add a commit to allow showing pending merges.
104
92
wt.commit('create a parent to allow testing merge output')
106
wt.add_parent_tree_id(b'pending@pending-0-0')
94
wt.add_parent_tree_id('pending@pending-0-0')
107
95
self.assertStatus([
111
'pending merge tips: (use -v to see all merge revisions)\n',
112
' (ghost) pending@pending-0-0\n',
99
'pending merge tips: (use -v to see all merge revisions)\n',
100
' (ghost) pending@pending-0-0\n',
115
103
self.assertStatus([
120
' (ghost) pending@pending-0-0\n',
108
' (ghost) pending@pending-0-0\n',
122
110
wt, verbose=True)
123
111
self.assertStatus([
126
'P (ghost) pending@pending-0-0\n',
114
'P (ghost) pending@pending-0-0\n',
129
117
self.assertStatus([
134
122
wt, pending=False)
135
123
self.assertStatus([
139
127
wt, short=True, pending=False)
185
173
self.assertEndsWith(message, "Empty commit 2\n")
186
174
wt2.commit("merged")
187
175
# must be long to make sure we see elipsis at the end
188
wt.commit("Empty commit 3 "
189
+ "blah blah blah blah " * 100)
176
wt.commit("Empty commit 3 " +
177
"blah blah blah blah " * 100)
190
178
wt2.merge_from_branch(wt.branch)
191
179
message = self.status_string(wt2, verbose=True)
192
180
self.assertStartsWith(message, "pending merges:\n")
193
self.assertTrue("Empty commit 3" in message)
181
self.assert_("Empty commit 3" in message)
194
182
self.assertEndsWith(message, "...\n")
196
184
def test_tree_status_ignores(self):
200
188
wt.commit('commit .bzrignore')
201
189
self.build_tree(['foo.c', 'foo.c~'])
202
190
self.assertStatus([
207
195
self.assertStatus([
212
200
def test_tree_status_specific_files(self):
213
201
"""Tests branch status with given specific files"""
214
202
wt = self.make_branch_and_tree('.')
217
self.build_tree(['directory/', 'directory/hello.c',
218
'bye.c', 'test.c', 'dir2/',
205
self.build_tree(['directory/','directory/hello.c', 'bye.c','test.c','dir2/'])
220
206
wt.add('directory')
222
208
wt.commit('testing')
232
' directory/hello.c\n'
239
'? directory/hello.c\n',
214
' directory/hello.c\n'
221
'? directory/hello.c\n'
245
226
self.assertRaises(errors.PathsDoNotExist,
246
227
show_tree_status,
247
wt, specific_files=['bye.c', 'test.c', 'absent.c'],
228
wt, specific_files=['bye.c','test.c','absent.c'],
251
232
show_tree_status(wt, specific_files=['directory'], to_file=tof)
253
self.assertEqual(tof.readlines(),
255
' directory/hello.c\n'
234
self.assertEquals(tof.readlines(),
236
' directory/hello.c\n'
258
239
show_tree_status(wt, specific_files=['directory'], to_file=tof,
261
self.assertEqual(tof.readlines(), ['? directory/hello.c\n'])
242
self.assertEquals(tof.readlines(), ['? directory/hello.c\n'])
264
245
show_tree_status(wt, specific_files=['dir2'], to_file=tof)
266
self.assertEqual(tof.readlines(),
247
self.assertEquals(tof.readlines(),
271
252
show_tree_status(wt, specific_files=['dir2'], to_file=tof, short=True)
273
self.assertEqual(tof.readlines(), ['? dir2/\n'])
254
self.assertEquals(tof.readlines(), ['? dir2/\n'])
276
257
revs = [RevisionSpec.from_string('0'), RevisionSpec.from_string('1')]
277
258
show_tree_status(wt, specific_files=['test.c'], to_file=tof,
278
259
short=True, revision=revs)
280
self.assertEqual(tof.readlines(), ['+N test.c\n'])
283
show_tree_status(wt, specific_files=['missing.c'], to_file=tof)
285
self.assertEqual(tof.readlines(),
290
show_tree_status(wt, specific_files=['missing.c'], to_file=tof,
293
self.assertEqual(tof.readlines(),
261
self.assertEquals(tof.readlines(), ['+N test.c\n'])
296
263
def test_specific_files_conflicts(self):
297
264
tree = self.make_branch_and_tree('.')
298
265
self.build_tree(['dir2/'])
300
267
tree.commit('added dir2')
301
tree.set_conflicts([conflicts.ContentsConflict('foo')])
268
tree.set_conflicts(conflicts.ConflictList(
269
[conflicts.ContentsConflict('foo')]))
303
271
show_tree_status(tree, specific_files=['dir2'], to_file=tof)
304
self.assertEqualDiff(b'', tof.getvalue())
305
tree.set_conflicts([conflicts.ContentsConflict('dir2')])
272
self.assertEqualDiff('', tof.getvalue())
273
tree.set_conflicts(conflicts.ConflictList(
274
[conflicts.ContentsConflict('dir2')]))
307
276
show_tree_status(tree, specific_files=['dir2'], to_file=tof)
308
277
self.assertEqualDiff('conflicts:\n Contents conflict in dir2\n',
311
tree.set_conflicts([conflicts.ContentsConflict('dir2/file1')])
280
tree.set_conflicts(conflicts.ConflictList(
281
[conflicts.ContentsConflict('dir2/file1')]))
313
283
show_tree_status(tree, specific_files=['dir2'], to_file=tof)
314
284
self.assertEqualDiff('conflicts:\n Contents conflict in dir2/file1\n',
326
296
wt.commit('Create five empty files.')
327
with open('FILE_B', 'w') as f:
328
f.write('Modification to file FILE_B.')
329
with open('FILE_C', 'w') as f:
330
f.write('Modification to file FILE_C.')
297
open('FILE_B', 'w').write('Modification to file FILE_B.')
298
open('FILE_C', 'w').write('Modification to file FILE_C.')
331
299
unlink('FILE_E') # FILE_E will be versioned but missing
332
with open('FILE_Q', 'w') as f:
333
f.write('FILE_Q is added but not committed.')
300
open('FILE_Q', 'w').write('FILE_Q is added but not committed.')
334
301
wt.add('FILE_Q') # FILE_Q will be added but not committed
335
302
open('UNVERSIONED_BUT_EXISTING', 'w')
363
330
# Okay, everything's looking good with the existent files.
364
331
# Let's see what happens when we throw in non-existent files.
366
# brz st [--short] NONEXISTENT '
333
# bzr st [--short] NONEXISTENT '
371
338
out, err = self.run_bzr('status NONEXISTENT', retcode=3)
372
339
self.assertEqual(expected, out.splitlines(True))
373
340
self.assertContainsRe(err,
374
341
r'.*ERROR: Path\(s\) do not exist: '
379
346
out, err = self.run_bzr('status --short NONEXISTENT', retcode=3)
380
347
self.assertContainsRe(err,
381
348
r'.*ERROR: Path\(s\) do not exist: '
384
351
def test_status_nonexistent_file_with_others(self):
385
# brz st [--short] NONEXISTENT ...others..
352
# bzr st [--short] NONEXISTENT ...others..
386
353
wt = self._prepare_nonexistent()
396
363
out, err = self.run_bzr('status NONEXISTENT '
397
364
'FILE_A FILE_B FILE_C FILE_D FILE_E',
472
439
self.assertContainsRe(err,
473
440
r'.*ERROR: Path\(s\) do not exist: '
477
'? UNVERSIONED_BUT_EXISTING\n',
444
'? UNVERSIONED_BUT_EXISTING\n',
483
450
out, err = self.run_bzr('status --short NONEXISTENT '
484
451
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
485
452
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
486
actual = out.splitlines(True)
488
self.assertEqual(expected, actual)
453
self.assertEqual(expected, out.splitlines(True))
489
454
self.assertContainsRe(err,
490
455
r'.*ERROR: Path\(s\) do not exist: '
493
458
def test_status_out_of_date(self):
494
459
"""Simulate status of out-of-date tree after remote push"""
495
460
tree = self.make_branch_and_tree('.')
496
self.build_tree_contents([('a', b'foo\n')])
497
with tree.lock_write():
461
self.build_tree_contents([('a', 'foo\n')])
499
465
tree.commit('add test file')
500
466
# simulate what happens after a remote push
501
tree.set_last_revision(b"0")
467
tree.set_last_revision("0")
469
# before run another commands we should unlock tree
502
471
out, err = self.run_bzr('status')
503
self.assertEqual("working tree is out of date, run 'brz update'\n",
472
self.assertEqual("working tree is out of date, run 'bzr update'\n",
506
475
def test_status_on_ignored(self):
514
483
result = self.run_bzr('status')[0]
515
484
self.assertContainsRe(result, "unknown:\n test1.c\n")
516
485
short_result = self.run_bzr('status --short')[0]
517
self.assertContainsRe(short_result, "\\? test1.c\n")
486
self.assertContainsRe(short_result, "\? test1.c\n")
519
488
result = self.run_bzr('status test1.c')[0]
520
489
self.assertContainsRe(result, "unknown:\n test1.c\n")
521
490
short_result = self.run_bzr('status --short test1.c')[0]
522
self.assertContainsRe(short_result, "\\? test1.c\n")
491
self.assertContainsRe(short_result, "\? test1.c\n")
524
493
result = self.run_bzr('status test1.c~')[0]
525
494
self.assertContainsRe(result, "ignored:\n test1.c~\n")
532
501
self.assertContainsRe(short_result, "I test1.c~\nI test2.c~\n")
534
503
result = self.run_bzr('status test1.c test1.c~ test2.c~')[0]
535
self.assertContainsRe(
536
result, "unknown:\n test1.c\nignored:\n test1.c~\n test2.c~\n")
537
short_result = self.run_bzr(
538
'status --short test1.c test1.c~ test2.c~')[0]
539
self.assertContainsRe(
540
short_result, "\\? test1.c\nI test1.c~\nI test2.c~\n")
504
self.assertContainsRe(result, "unknown:\n test1.c\nignored:\n test1.c~\n test2.c~\n")
505
short_result = self.run_bzr('status --short test1.c test1.c~ test2.c~')[0]
506
self.assertContainsRe(short_result, "\? test1.c\nI test1.c~\nI test2.c~\n")
542
508
def test_status_write_lock(self):
543
509
"""Test that status works without fetching history and
549
515
wt = self.make_branch_and_tree('branch1')
551
517
wt.commit('Empty commit 1')
552
wt2 = b.controldir.sprout('branch2').open_workingtree()
518
wt2 = b.bzrdir.sprout('branch2').open_workingtree()
553
519
wt2.commit('Empty commit 2')
554
520
out, err = self.run_bzr('status branch1 -rbranch:branch2')
555
521
self.assertEqual('', out)
557
def test_status_with_shelves(self):
558
"""Ensure that _show_shelve_summary handler works.
560
wt = self.make_branch_and_tree('.')
561
self.build_tree(['hello.c'])
563
self.run_bzr(['shelve', '--all', '-m', 'foo'])
564
self.build_tree(['bye.c'])
569
'1 shelf exists. See "brz shelve --list" for details.\n',
572
self.run_bzr(['shelve', '--all', '-m', 'bar'])
573
self.build_tree(['eggs.c', 'spam.c'])
580
'2 shelves exist. See "brz shelve --list" for details.\n',
588
specific_files=['spam.c'])
591
524
class CheckoutStatus(BranchStatus):
645
579
self.assertContainsRe(result, "[+]N hello.txt\n")
647
581
self.build_tree(['world.txt'])
648
result = self.run_bzr("status -S -r 0")[0]
649
self.assertContainsRe(result, "[+]N hello.txt\n"
582
result = self.run_bzr("status --short -r 0")[0]
583
self.assertContainsRe(result, "[+]N hello.txt\n" \
650
584
"[?] world.txt\n")
651
result2 = self.run_bzr("status -S -r 0..")[0]
652
self.assertEqual(result2, result)
585
result2 = self.run_bzr("status --short -r 0..")[0]
586
self.assertEquals(result2, result)
654
588
def test_status_versioned(self):
655
589
tree = self.make_branch_and_tree('.')
743
676
self.build_tree(['a/a'])
745
678
a_tree.commit('a')
746
b_tree = a_tree.controldir.sprout('b').open_workingtree()
679
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
747
680
self.build_tree(['b/b'])
749
682
b_tree.commit('b')
751
684
self.run_bzr('merge ../b', working_dir='a')
752
685
out, err = self.run_bzr('status --no-pending', working_dir='a')
753
self.assertEqual(out, "added:\n b\n")
686
self.assertEquals(out, "added:\n b\n")
755
688
def test_pending_specific_files(self):
756
689
"""With a specific file list, pending merges are not shown."""
757
690
tree = self.make_branch_and_tree('tree')
758
self.build_tree_contents([('tree/a', b'content of a\n')])
691
self.build_tree_contents([('tree/a', 'content of a\n')])
760
693
r1_id = tree.commit('one')
761
alt = tree.controldir.sprout('alt').open_workingtree()
762
self.build_tree_contents([('alt/a', b'content of a\nfrom alt\n')])
694
alt = tree.bzrdir.sprout('alt').open_workingtree()
695
self.build_tree_contents([('alt/a', 'content of a\nfrom alt\n')])
763
696
alt_id = alt.commit('alt')
764
697
tree.merge_from_branch(alt.branch)
765
698
output = self.make_utf8_encoded_stringio()
766
699
show_tree_status(tree, to_file=output)
767
self.assertContainsRe(output.getvalue(), b'pending merge')
700
self.assertContainsRe(output.getvalue(), 'pending merge')
768
701
out, err = self.run_bzr('status tree/a')
769
702
self.assertNotContainsRe(out, 'pending merge')
772
705
class TestStatusEncodings(TestCaseWithTransport):
708
TestCaseWithTransport.setUp(self)
709
self.user_encoding = osutils._cached_user_encoding
710
self.stdout = sys.stdout
713
osutils._cached_user_encoding = self.user_encoding
714
sys.stdout = self.stdout
715
TestCaseWithTransport.tearDown(self)
774
717
def make_uncommitted_tree(self):
775
718
"""Build a branch with uncommitted unicode named changes in the cwd."""
776
719
working_tree = self.make_branch_and_tree(u'.')
777
720
filename = u'hell\u00d8'
779
self.build_tree_contents([(filename, b'contents of hello')])
722
self.build_tree_contents([(filename, 'contents of hello')])
780
723
except UnicodeEncodeError:
781
724
raise TestSkipped("can't build unicode working tree in "
782
"filesystem encoding %s" % sys.getfilesystemencoding())
725
"filesystem encoding %s" % sys.getfilesystemencoding())
783
726
working_tree.add(filename)
784
727
return working_tree
786
729
def test_stdout_ascii(self):
787
self.overrideAttr(osutils, '_cached_user_encoding', 'ascii')
730
sys.stdout = StringIO()
731
osutils._cached_user_encoding = 'ascii'
788
732
working_tree = self.make_uncommitted_tree()
789
733
stdout, stderr = self.run_bzr("status")
791
self.assertEqual(stdout, """\
735
self.assertEquals(stdout, """\
796
740
def test_stdout_latin1(self):
797
self.overrideAttr(osutils, '_cached_user_encoding', 'latin-1')
741
sys.stdout = StringIO()
742
osutils._cached_user_encoding = 'latin-1'
798
743
working_tree = self.make_uncommitted_tree()
799
744
stdout, stderr = self.run_bzr('status')
746
self.assertEquals(stdout, u"""\
806
expected = expected.encode('latin-1')
807
self.assertEqual(stdout, expected)
749
""".encode('latin-1'))