22
22
interface later, they will be non blackbox tests.
25
from cStringIO import StringIO
27
26
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
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
45
51
class BranchStatus(TestCaseWithTransport):
47
def assertStatus(self, expected_lines, working_tree,
48
revision=None, short=False, pending=True, verbose=False):
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):
49
63
"""Run status in working_tree and look for output.
51
65
:param expected_lines: The lines to look for.
52
66
:param working_tree: The tree to run status in.
54
output_string = self.status_string(working_tree, revision, short,
68
output_string = self.status_string(working_tree, specific_files, revision, short,
56
70
self.assertEqual(expected_lines, output_string.splitlines(True))
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')
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')
68
80
def test_branch_status(self):
69
81
"""Test basic branch status"""
78
90
self.build_tree(['hello.c', 'bye.c'])
79
91
self.assertStatus([
85
97
self.assertStatus([
91
103
# add a commit to allow showing pending merges.
92
104
wt.commit('create a parent to allow testing merge output')
94
wt.add_parent_tree_id('pending@pending-0-0')
106
wt.add_parent_tree_id(b'pending@pending-0-0')
95
107
self.assertStatus([
99
'pending merge tips: (use -v to see all merge revisions)\n',
100
' (ghost) pending@pending-0-0\n',
111
'pending merge tips: (use -v to see all merge revisions)\n',
112
' (ghost) pending@pending-0-0\n',
103
115
self.assertStatus([
108
' (ghost) pending@pending-0-0\n',
120
' (ghost) pending@pending-0-0\n',
110
122
wt, verbose=True)
111
123
self.assertStatus([
114
'P (ghost) pending@pending-0-0\n',
126
'P (ghost) pending@pending-0-0\n',
117
129
self.assertStatus([
122
134
wt, pending=False)
123
135
self.assertStatus([
127
139
wt, short=True, pending=False)
173
185
self.assertEndsWith(message, "Empty commit 2\n")
174
186
wt2.commit("merged")
175
187
# must be long to make sure we see elipsis at the end
176
wt.commit("Empty commit 3 " +
177
"blah blah blah blah " * 100)
188
wt.commit("Empty commit 3 "
189
+ "blah blah blah blah " * 100)
178
190
wt2.merge_from_branch(wt.branch)
179
191
message = self.status_string(wt2, verbose=True)
180
192
self.assertStartsWith(message, "pending merges:\n")
181
self.assert_("Empty commit 3" in message)
193
self.assertTrue("Empty commit 3" in message)
182
194
self.assertEndsWith(message, "...\n")
184
196
def test_tree_status_ignores(self):
188
200
wt.commit('commit .bzrignore')
189
201
self.build_tree(['foo.c', 'foo.c~'])
190
202
self.assertStatus([
195
207
self.assertStatus([
200
212
def test_tree_status_specific_files(self):
201
213
"""Tests branch status with given specific files"""
202
214
wt = self.make_branch_and_tree('.')
205
self.build_tree(['directory/','directory/hello.c', 'bye.c','test.c','dir2/'])
217
self.build_tree(['directory/', 'directory/hello.c',
218
'bye.c', 'test.c', 'dir2/',
206
220
wt.add('directory')
208
222
wt.commit('testing')
214
' directory/hello.c\n'
221
'? directory/hello.c\n'
232
' directory/hello.c\n'
239
'? directory/hello.c\n',
226
245
self.assertRaises(errors.PathsDoNotExist,
227
246
show_tree_status,
228
wt, specific_files=['bye.c','test.c','absent.c'],
247
wt, specific_files=['bye.c', 'test.c', 'absent.c'],
232
251
show_tree_status(wt, specific_files=['directory'], to_file=tof)
234
self.assertEquals(tof.readlines(),
236
' directory/hello.c\n'
253
self.assertEqual(tof.readlines(),
255
' directory/hello.c\n'
239
258
show_tree_status(wt, specific_files=['directory'], to_file=tof,
242
self.assertEquals(tof.readlines(), ['? directory/hello.c\n'])
261
self.assertEqual(tof.readlines(), ['? directory/hello.c\n'])
245
264
show_tree_status(wt, specific_files=['dir2'], to_file=tof)
247
self.assertEquals(tof.readlines(),
266
self.assertEqual(tof.readlines(),
252
271
show_tree_status(wt, specific_files=['dir2'], to_file=tof, short=True)
254
self.assertEquals(tof.readlines(), ['? dir2/\n'])
273
self.assertEqual(tof.readlines(), ['? dir2/\n'])
257
276
revs = [RevisionSpec.from_string('0'), RevisionSpec.from_string('1')]
258
277
show_tree_status(wt, specific_files=['test.c'], to_file=tof,
259
278
short=True, revision=revs)
261
self.assertEquals(tof.readlines(), ['+N test.c\n'])
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(),
263
296
def test_specific_files_conflicts(self):
264
297
tree = self.make_branch_and_tree('.')
296
329
wt.commit('Create five empty files.')
297
open('FILE_B', 'w').write('Modification to file FILE_B.')
298
open('FILE_C', 'w').write('Modification to file FILE_C.')
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.')
299
334
unlink('FILE_E') # FILE_E will be versioned but missing
300
open('FILE_Q', 'w').write('FILE_Q is added but not committed.')
335
with open('FILE_Q', 'w') as f:
336
f.write('FILE_Q is added but not committed.')
301
337
wt.add('FILE_Q') # FILE_Q will be added but not committed
302
338
open('UNVERSIONED_BUT_EXISTING', 'w')
330
366
# Okay, everything's looking good with the existent files.
331
367
# Let's see what happens when we throw in non-existent files.
333
# bzr st [--short] NONEXISTENT '
369
# brz st [--short] NONEXISTENT '
338
374
out, err = self.run_bzr('status NONEXISTENT', retcode=3)
339
375
self.assertEqual(expected, out.splitlines(True))
340
376
self.assertContainsRe(err,
341
377
r'.*ERROR: Path\(s\) do not exist: '
346
382
out, err = self.run_bzr('status --short NONEXISTENT', retcode=3)
347
383
self.assertContainsRe(err,
348
384
r'.*ERROR: Path\(s\) do not exist: '
351
387
def test_status_nonexistent_file_with_others(self):
352
# bzr st [--short] NONEXISTENT ...others..
388
# brz st [--short] NONEXISTENT ...others..
353
389
wt = self._prepare_nonexistent()
363
399
out, err = self.run_bzr('status NONEXISTENT '
364
400
'FILE_A FILE_B FILE_C FILE_D FILE_E',
384
420
def test_status_multiple_nonexistent_files(self):
385
# bzr st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
421
# brz st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
386
422
wt = self._prepare_nonexistent()
394
' ANOTHER_NONEXISTENT\n',
430
' ANOTHER_NONEXISTENT\n',
397
433
out, err = self.run_bzr('status NONEXISTENT '
398
434
'FILE_A FILE_B ANOTHER_NONEXISTENT '
399
435
'FILE_C FILE_D FILE_E', retcode=3)
417
453
'ANOTHER_NONEXISTENT NONEXISTENT.*')
419
455
def test_status_nonexistent_file_with_unversioned(self):
420
# bzr st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
456
# brz st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
421
457
wt = self._prepare_nonexistent()
431
' UNVERSIONED_BUT_EXISTING\n',
467
' UNVERSIONED_BUT_EXISTING\n',
435
471
out, err = self.run_bzr('status NONEXISTENT '
436
472
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
437
473
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
439
475
self.assertContainsRe(err,
440
476
r'.*ERROR: Path\(s\) do not exist: '
444
'? UNVERSIONED_BUT_EXISTING\n',
480
'? UNVERSIONED_BUT_EXISTING\n',
450
486
out, err = self.run_bzr('status --short NONEXISTENT '
451
487
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
452
488
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
453
self.assertEqual(expected, out.splitlines(True))
489
actual = out.splitlines(True)
491
self.assertEqual(expected, actual)
454
492
self.assertContainsRe(err,
455
493
r'.*ERROR: Path\(s\) do not exist: '
458
496
def test_status_out_of_date(self):
459
497
"""Simulate status of out-of-date tree after remote push"""
460
498
tree = self.make_branch_and_tree('.')
461
self.build_tree_contents([('a', 'foo\n')])
499
self.build_tree_contents([('a', b'foo\n')])
462
500
tree.lock_write()
465
503
tree.commit('add test file')
466
504
# simulate what happens after a remote push
467
tree.set_last_revision("0")
505
tree.set_last_revision(b"0")
469
507
# before run another commands we should unlock tree
471
509
out, err = self.run_bzr('status')
472
self.assertEqual("working tree is out of date, run 'bzr update'\n",
510
self.assertEqual("working tree is out of date, run 'brz update'\n",
475
513
def test_status_on_ignored(self):
483
521
result = self.run_bzr('status')[0]
484
522
self.assertContainsRe(result, "unknown:\n test1.c\n")
485
523
short_result = self.run_bzr('status --short')[0]
486
self.assertContainsRe(short_result, "\? test1.c\n")
524
self.assertContainsRe(short_result, "\\? test1.c\n")
488
526
result = self.run_bzr('status test1.c')[0]
489
527
self.assertContainsRe(result, "unknown:\n test1.c\n")
490
528
short_result = self.run_bzr('status --short test1.c')[0]
491
self.assertContainsRe(short_result, "\? test1.c\n")
529
self.assertContainsRe(short_result, "\\? test1.c\n")
493
531
result = self.run_bzr('status test1.c~')[0]
494
532
self.assertContainsRe(result, "ignored:\n test1.c~\n")
501
539
self.assertContainsRe(short_result, "I test1.c~\nI test2.c~\n")
503
541
result = self.run_bzr('status test1.c test1.c~ test2.c~')[0]
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
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")
508
549
def test_status_write_lock(self):
509
550
"""Test that status works without fetching history and
515
556
wt = self.make_branch_and_tree('branch1')
517
558
wt.commit('Empty commit 1')
518
wt2 = b.bzrdir.sprout('branch2').open_workingtree()
559
wt2 = b.controldir.sprout('branch2').open_workingtree()
519
560
wt2.commit('Empty commit 2')
520
561
out, err = self.run_bzr('status branch1 -rbranch:branch2')
521
562
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'])
524
598
class CheckoutStatus(BranchStatus):
559
632
self.build_tree(['world.txt'])
560
633
result = self.run_bzr("status -r 0")[0]
561
self.assertContainsRe(result, "added:\n hello.txt\n" \
634
self.assertContainsRe(result, "added:\n hello.txt\n"
562
635
"unknown:\n world.txt\n")
563
636
result2 = self.run_bzr("status -r 0..")[0]
564
self.assertEquals(result2, result)
637
self.assertEqual(result2, result)
566
639
def test_status_short(self):
567
640
tree = self.make_branch_and_tree('.')
579
652
self.assertContainsRe(result, "[+]N hello.txt\n")
581
654
self.build_tree(['world.txt'])
582
result = self.run_bzr("status --short -r 0")[0]
583
self.assertContainsRe(result, "[+]N hello.txt\n" \
655
result = self.run_bzr("status -S -r 0")[0]
656
self.assertContainsRe(result, "[+]N hello.txt\n"
584
657
"[?] world.txt\n")
585
result2 = self.run_bzr("status --short -r 0..")[0]
586
self.assertEquals(result2, result)
658
result2 = self.run_bzr("status -S -r 0..")[0]
659
self.assertEqual(result2, result)
588
661
def test_status_versioned(self):
589
662
tree = self.make_branch_and_tree('.')
644
717
tree.commit('added file')
646
719
self.build_tree(['file/'])
647
self.assertStatusContains('kind changed:\n file \(file => directory\)')
720
self.assertStatusContains(
721
'kind changed:\n file \\(file => directory\\)')
648
722
tree.rename_one('file', 'directory')
649
self.assertStatusContains('renamed:\n file/ => directory/\n' \
723
self.assertStatusContains('renamed:\n file/ => directory/\n'
650
724
'modified:\n directory/\n')
651
725
rmdir('directory')
652
726
self.assertStatusContains('removed:\n file\n')
676
750
self.build_tree(['a/a'])
678
752
a_tree.commit('a')
679
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
753
b_tree = a_tree.controldir.sprout('b').open_workingtree()
680
754
self.build_tree(['b/b'])
682
756
b_tree.commit('b')
684
758
self.run_bzr('merge ../b', working_dir='a')
685
759
out, err = self.run_bzr('status --no-pending', working_dir='a')
686
self.assertEquals(out, "added:\n b\n")
760
self.assertEqual(out, "added:\n b\n")
688
762
def test_pending_specific_files(self):
689
763
"""With a specific file list, pending merges are not shown."""
690
764
tree = self.make_branch_and_tree('tree')
691
self.build_tree_contents([('tree/a', 'content of a\n')])
765
self.build_tree_contents([('tree/a', b'content of a\n')])
693
767
r1_id = tree.commit('one')
694
alt = tree.bzrdir.sprout('alt').open_workingtree()
695
self.build_tree_contents([('alt/a', 'content of a\nfrom alt\n')])
768
alt = tree.controldir.sprout('alt').open_workingtree()
769
self.build_tree_contents([('alt/a', b'content of a\nfrom alt\n')])
696
770
alt_id = alt.commit('alt')
697
771
tree.merge_from_branch(alt.branch)
698
772
output = self.make_utf8_encoded_stringio()
699
773
show_tree_status(tree, to_file=output)
700
self.assertContainsRe(output.getvalue(), 'pending merge')
774
self.assertContainsRe(output.getvalue(), b'pending merge')
701
775
out, err = self.run_bzr('status tree/a')
702
776
self.assertNotContainsRe(out, 'pending merge')
705
779
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)
717
781
def make_uncommitted_tree(self):
718
782
"""Build a branch with uncommitted unicode named changes in the cwd."""
719
783
working_tree = self.make_branch_and_tree(u'.')
720
784
filename = u'hell\u00d8'
722
self.build_tree_contents([(filename, 'contents of hello')])
786
self.build_tree_contents([(filename, b'contents of hello')])
723
787
except UnicodeEncodeError:
724
788
raise TestSkipped("can't build unicode working tree in "
725
"filesystem encoding %s" % sys.getfilesystemencoding())
789
"filesystem encoding %s" % sys.getfilesystemencoding())
726
790
working_tree.add(filename)
727
791
return working_tree
729
793
def test_stdout_ascii(self):
730
sys.stdout = StringIO()
731
osutils._cached_user_encoding = 'ascii'
794
self.overrideAttr(osutils, '_cached_user_encoding', 'ascii')
732
795
working_tree = self.make_uncommitted_tree()
733
796
stdout, stderr = self.run_bzr("status")
735
self.assertEquals(stdout, """\
798
self.assertEqual(stdout, """\
740
803
def test_stdout_latin1(self):
741
sys.stdout = StringIO()
742
osutils._cached_user_encoding = 'latin-1'
804
self.overrideAttr(osutils, '_cached_user_encoding', 'latin-1')
743
805
working_tree = self.make_uncommitted_tree()
744
806
stdout, stderr = self.run_bzr('status')
746
self.assertEquals(stdout, u"""\
749
""".encode('latin-1'))
813
expected = expected.encode('latin-1')
814
self.assertEqual(stdout, expected)