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
35
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('.')
329
296
wt.commit('Create five empty files.')
330
with open('FILE_B', 'w') as f:
331
f.write('Modification to file FILE_B.')
332
with open('FILE_C', 'w') as f:
333
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.')
334
299
unlink('FILE_E') # FILE_E will be versioned but missing
335
with open('FILE_Q', 'w') as f:
336
f.write('FILE_Q is added but not committed.')
300
open('FILE_Q', 'w').write('FILE_Q is added but not committed.')
337
301
wt.add('FILE_Q') # FILE_Q will be added but not committed
338
302
open('UNVERSIONED_BUT_EXISTING', 'w')
366
330
# Okay, everything's looking good with the existent files.
367
331
# Let's see what happens when we throw in non-existent files.
369
# brz st [--short] NONEXISTENT '
333
# bzr st [--short] NONEXISTENT '
374
338
out, err = self.run_bzr('status NONEXISTENT', retcode=3)
375
339
self.assertEqual(expected, out.splitlines(True))
376
340
self.assertContainsRe(err,
377
341
r'.*ERROR: Path\(s\) do not exist: '
382
346
out, err = self.run_bzr('status --short NONEXISTENT', retcode=3)
383
347
self.assertContainsRe(err,
384
348
r'.*ERROR: Path\(s\) do not exist: '
387
351
def test_status_nonexistent_file_with_others(self):
388
# brz st [--short] NONEXISTENT ...others..
352
# bzr st [--short] NONEXISTENT ...others..
389
353
wt = self._prepare_nonexistent()
399
363
out, err = self.run_bzr('status NONEXISTENT '
400
364
'FILE_A FILE_B FILE_C FILE_D FILE_E',
420
384
def test_status_multiple_nonexistent_files(self):
421
# brz st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
385
# bzr st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
422
386
wt = self._prepare_nonexistent()
430
' ANOTHER_NONEXISTENT\n',
394
' ANOTHER_NONEXISTENT\n',
433
397
out, err = self.run_bzr('status NONEXISTENT '
434
398
'FILE_A FILE_B ANOTHER_NONEXISTENT '
435
399
'FILE_C FILE_D FILE_E', retcode=3)
453
417
'ANOTHER_NONEXISTENT NONEXISTENT.*')
455
419
def test_status_nonexistent_file_with_unversioned(self):
456
# brz st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
420
# bzr st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
457
421
wt = self._prepare_nonexistent()
467
' UNVERSIONED_BUT_EXISTING\n',
431
' UNVERSIONED_BUT_EXISTING\n',
471
435
out, err = self.run_bzr('status NONEXISTENT '
472
436
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
473
437
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
475
439
self.assertContainsRe(err,
476
440
r'.*ERROR: Path\(s\) do not exist: '
480
'? UNVERSIONED_BUT_EXISTING\n',
444
'? UNVERSIONED_BUT_EXISTING\n',
486
450
out, err = self.run_bzr('status --short NONEXISTENT '
487
451
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
488
452
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
489
actual = out.splitlines(True)
491
self.assertEqual(expected, actual)
453
self.assertEqual(expected, out.splitlines(True))
492
454
self.assertContainsRe(err,
493
455
r'.*ERROR: Path\(s\) do not exist: '
496
458
def test_status_out_of_date(self):
497
459
"""Simulate status of out-of-date tree after remote push"""
498
460
tree = self.make_branch_and_tree('.')
499
self.build_tree_contents([('a', b'foo\n')])
461
self.build_tree_contents([('a', 'foo\n')])
500
462
tree.lock_write()
503
465
tree.commit('add test file')
504
466
# simulate what happens after a remote push
505
tree.set_last_revision(b"0")
467
tree.set_last_revision("0")
507
469
# before run another commands we should unlock tree
509
471
out, err = self.run_bzr('status')
510
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",
513
475
def test_status_on_ignored(self):
521
483
result = self.run_bzr('status')[0]
522
484
self.assertContainsRe(result, "unknown:\n test1.c\n")
523
485
short_result = self.run_bzr('status --short')[0]
524
self.assertContainsRe(short_result, "\\? test1.c\n")
486
self.assertContainsRe(short_result, "\? test1.c\n")
526
488
result = self.run_bzr('status test1.c')[0]
527
489
self.assertContainsRe(result, "unknown:\n test1.c\n")
528
490
short_result = self.run_bzr('status --short test1.c')[0]
529
self.assertContainsRe(short_result, "\\? test1.c\n")
491
self.assertContainsRe(short_result, "\? test1.c\n")
531
493
result = self.run_bzr('status test1.c~')[0]
532
494
self.assertContainsRe(result, "ignored:\n test1.c~\n")
539
501
self.assertContainsRe(short_result, "I test1.c~\nI test2.c~\n")
541
503
result = self.run_bzr('status test1.c test1.c~ test2.c~')[0]
542
self.assertContainsRe(
543
result, "unknown:\n test1.c\nignored:\n test1.c~\n test2.c~\n")
544
short_result = self.run_bzr(
545
'status --short test1.c test1.c~ test2.c~')[0]
546
self.assertContainsRe(
547
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")
549
508
def test_status_write_lock(self):
550
509
"""Test that status works without fetching history and
556
515
wt = self.make_branch_and_tree('branch1')
558
517
wt.commit('Empty commit 1')
559
wt2 = b.controldir.sprout('branch2').open_workingtree()
518
wt2 = b.bzrdir.sprout('branch2').open_workingtree()
560
519
wt2.commit('Empty commit 2')
561
520
out, err = self.run_bzr('status branch1 -rbranch:branch2')
562
521
self.assertEqual('', out)
564
def test_status_with_shelves(self):
565
"""Ensure that _show_shelve_summary handler works.
567
wt = self.make_branch_and_tree('.')
568
self.build_tree(['hello.c'])
570
self.run_bzr(['shelve', '--all', '-m', 'foo'])
571
self.build_tree(['bye.c'])
576
'1 shelf exists. See "brz shelve --list" for details.\n',
579
self.run_bzr(['shelve', '--all', '-m', 'bar'])
580
self.build_tree(['eggs.c', 'spam.c'])
587
'2 shelves exist. See "brz shelve --list" for details.\n',
595
specific_files=['spam.c'])
598
524
class CheckoutStatus(BranchStatus):
632
559
self.build_tree(['world.txt'])
633
560
result = self.run_bzr("status -r 0")[0]
634
self.assertContainsRe(result, "added:\n hello.txt\n"
561
self.assertContainsRe(result, "added:\n hello.txt\n" \
635
562
"unknown:\n world.txt\n")
636
563
result2 = self.run_bzr("status -r 0..")[0]
637
self.assertEqual(result2, result)
564
self.assertEquals(result2, result)
639
566
def test_status_short(self):
640
567
tree = self.make_branch_and_tree('.')
652
579
self.assertContainsRe(result, "[+]N hello.txt\n")
654
581
self.build_tree(['world.txt'])
655
result = self.run_bzr("status -S -r 0")[0]
656
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" \
657
584
"[?] world.txt\n")
658
result2 = self.run_bzr("status -S -r 0..")[0]
659
self.assertEqual(result2, result)
585
result2 = self.run_bzr("status --short -r 0..")[0]
586
self.assertEquals(result2, result)
661
588
def test_status_versioned(self):
662
589
tree = self.make_branch_and_tree('.')
717
644
tree.commit('added file')
719
646
self.build_tree(['file/'])
720
self.assertStatusContains(
721
'kind changed:\n file \\(file => directory\\)')
647
self.assertStatusContains('kind changed:\n file \(file => directory\)')
722
648
tree.rename_one('file', 'directory')
723
self.assertStatusContains('renamed:\n file/ => directory/\n'
649
self.assertStatusContains('renamed:\n file/ => directory/\n' \
724
650
'modified:\n directory/\n')
725
651
rmdir('directory')
726
652
self.assertStatusContains('removed:\n file\n')
750
676
self.build_tree(['a/a'])
752
678
a_tree.commit('a')
753
b_tree = a_tree.controldir.sprout('b').open_workingtree()
679
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
754
680
self.build_tree(['b/b'])
756
682
b_tree.commit('b')
758
684
self.run_bzr('merge ../b', working_dir='a')
759
685
out, err = self.run_bzr('status --no-pending', working_dir='a')
760
self.assertEqual(out, "added:\n b\n")
686
self.assertEquals(out, "added:\n b\n")
762
688
def test_pending_specific_files(self):
763
689
"""With a specific file list, pending merges are not shown."""
764
690
tree = self.make_branch_and_tree('tree')
765
self.build_tree_contents([('tree/a', b'content of a\n')])
691
self.build_tree_contents([('tree/a', 'content of a\n')])
767
693
r1_id = tree.commit('one')
768
alt = tree.controldir.sprout('alt').open_workingtree()
769
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')])
770
696
alt_id = alt.commit('alt')
771
697
tree.merge_from_branch(alt.branch)
772
698
output = self.make_utf8_encoded_stringio()
773
699
show_tree_status(tree, to_file=output)
774
self.assertContainsRe(output.getvalue(), b'pending merge')
700
self.assertContainsRe(output.getvalue(), 'pending merge')
775
701
out, err = self.run_bzr('status tree/a')
776
702
self.assertNotContainsRe(out, 'pending merge')
779
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)
781
717
def make_uncommitted_tree(self):
782
718
"""Build a branch with uncommitted unicode named changes in the cwd."""
783
719
working_tree = self.make_branch_and_tree(u'.')
784
720
filename = u'hell\u00d8'
786
self.build_tree_contents([(filename, b'contents of hello')])
722
self.build_tree_contents([(filename, 'contents of hello')])
787
723
except UnicodeEncodeError:
788
724
raise TestSkipped("can't build unicode working tree in "
789
"filesystem encoding %s" % sys.getfilesystemencoding())
725
"filesystem encoding %s" % sys.getfilesystemencoding())
790
726
working_tree.add(filename)
791
727
return working_tree
793
729
def test_stdout_ascii(self):
794
self.overrideAttr(osutils, '_cached_user_encoding', 'ascii')
730
sys.stdout = StringIO()
731
osutils._cached_user_encoding = 'ascii'
795
732
working_tree = self.make_uncommitted_tree()
796
733
stdout, stderr = self.run_bzr("status")
798
self.assertEqual(stdout, """\
735
self.assertEquals(stdout, """\
803
740
def test_stdout_latin1(self):
804
self.overrideAttr(osutils, '_cached_user_encoding', 'latin-1')
741
sys.stdout = StringIO()
742
osutils._cached_user_encoding = 'latin-1'
805
743
working_tree = self.make_uncommitted_tree()
806
744
stdout, stderr = self.run_bzr('status')
746
self.assertEquals(stdout, u"""\
813
expected = expected.encode('latin-1')
814
self.assertEqual(stdout, expected)
749
""".encode('latin-1'))