22
22
interface later, they will be non blackbox tests.
25
from cStringIO import StringIO
27
30
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
39
from breezy.bzr import (
43
from ...osutils import pathjoin
44
from ...revisionspec import RevisionSpec
45
from ...status import show_tree_status
46
from .. import TestCaseWithTransport, TestSkipped
47
from ...workingtree import WorkingTree
45
50
class BranchStatus(TestCaseWithTransport):
47
def assertStatus(self, expected_lines, working_tree,
48
revision=None, short=False, pending=True, verbose=False):
53
super(BranchStatus, self).setUp()
54
# As TestCase.setUp clears all hooks, we install this default
55
# post_status hook handler for the test.
56
status.hooks.install_named_hook('post_status',
57
status._show_shelve_summary,
60
def assertStatus(self, expected_lines, working_tree, specific_files=None,
61
revision=None, short=False, pending=True, verbose=False):
49
62
"""Run status in working_tree and look for output.
51
64
:param expected_lines: The lines to look for.
52
65
:param working_tree: The tree to run status in.
54
output_string = self.status_string(working_tree, revision, short,
67
output_string = self.status_string(working_tree, specific_files, revision, short,
56
69
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')
71
def status_string(self, wt, specific_files=None, revision=None,
72
short=False, pending=True, verbose=False):
73
uio = self.make_utf8_encoded_stringio()
74
show_tree_status(wt, specific_files=specific_files, to_file=uio,
75
revision=revision, short=short, show_pending=pending,
77
return uio.getvalue().decode('utf-8')
68
79
def test_branch_status(self):
69
80
"""Test basic branch status"""
78
89
self.build_tree(['hello.c', 'bye.c'])
79
90
self.assertStatus([
85
96
self.assertStatus([
91
102
# add a commit to allow showing pending merges.
92
103
wt.commit('create a parent to allow testing merge output')
94
wt.add_parent_tree_id('pending@pending-0-0')
105
wt.add_parent_tree_id(b'pending@pending-0-0')
95
106
self.assertStatus([
99
'pending merge tips: (use -v to see all merge revisions)\n',
100
' (ghost) pending@pending-0-0\n',
110
'pending merge tips: (use -v to see all merge revisions)\n',
111
' (ghost) pending@pending-0-0\n',
103
114
self.assertStatus([
108
' (ghost) pending@pending-0-0\n',
119
' (ghost) pending@pending-0-0\n',
110
121
wt, verbose=True)
111
122
self.assertStatus([
114
'P (ghost) pending@pending-0-0\n',
125
'P (ghost) pending@pending-0-0\n',
117
128
self.assertStatus([
122
133
wt, pending=False)
123
134
self.assertStatus([
127
138
wt, short=True, pending=False)
173
184
self.assertEndsWith(message, "Empty commit 2\n")
174
185
wt2.commit("merged")
175
186
# must be long to make sure we see elipsis at the end
176
wt.commit("Empty commit 3 " +
177
"blah blah blah blah " * 100)
187
wt.commit("Empty commit 3 "
188
+ "blah blah blah blah " * 100)
178
189
wt2.merge_from_branch(wt.branch)
179
190
message = self.status_string(wt2, verbose=True)
180
191
self.assertStartsWith(message, "pending merges:\n")
181
self.assert_("Empty commit 3" in message)
192
self.assertTrue("Empty commit 3" in message)
182
193
self.assertEndsWith(message, "...\n")
184
195
def test_tree_status_ignores(self):
188
199
wt.commit('commit .bzrignore')
189
200
self.build_tree(['foo.c', 'foo.c~'])
190
201
self.assertStatus([
195
206
self.assertStatus([
200
211
def test_tree_status_specific_files(self):
201
212
"""Tests branch status with given specific files"""
202
213
wt = self.make_branch_and_tree('.')
205
self.build_tree(['directory/','directory/hello.c', 'bye.c','test.c','dir2/'])
216
self.build_tree(['directory/', 'directory/hello.c',
217
'bye.c', 'test.c', 'dir2/',
206
219
wt.add('directory')
208
221
wt.commit('testing')
214
' directory/hello.c\n'
221
'? directory/hello.c\n'
231
' directory/hello.c\n'
238
'? directory/hello.c\n',
226
244
self.assertRaises(errors.PathsDoNotExist,
227
245
show_tree_status,
228
wt, specific_files=['bye.c','test.c','absent.c'],
246
wt, specific_files=['bye.c', 'test.c', 'absent.c'],
232
250
show_tree_status(wt, specific_files=['directory'], to_file=tof)
234
self.assertEquals(tof.readlines(),
236
' directory/hello.c\n'
252
self.assertEqual(tof.readlines(),
254
' directory/hello.c\n'
239
257
show_tree_status(wt, specific_files=['directory'], to_file=tof,
242
self.assertEquals(tof.readlines(), ['? directory/hello.c\n'])
260
self.assertEqual(tof.readlines(), ['? directory/hello.c\n'])
245
263
show_tree_status(wt, specific_files=['dir2'], to_file=tof)
247
self.assertEquals(tof.readlines(),
265
self.assertEqual(tof.readlines(),
252
270
show_tree_status(wt, specific_files=['dir2'], to_file=tof, short=True)
254
self.assertEquals(tof.readlines(), ['? dir2/\n'])
272
self.assertEqual(tof.readlines(), ['? dir2/\n'])
257
275
revs = [RevisionSpec.from_string('0'), RevisionSpec.from_string('1')]
258
276
show_tree_status(wt, specific_files=['test.c'], to_file=tof,
259
277
short=True, revision=revs)
261
self.assertEquals(tof.readlines(), ['+N test.c\n'])
279
self.assertEqual(tof.readlines(), ['+N test.c\n'])
282
show_tree_status(wt, specific_files=['missing.c'], to_file=tof)
284
self.assertEqual(tof.readlines(),
289
show_tree_status(wt, specific_files=['missing.c'], to_file=tof,
292
self.assertEqual(tof.readlines(),
263
295
def test_specific_files_conflicts(self):
264
296
tree = self.make_branch_and_tree('.')
296
328
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.')
329
with open('FILE_B', 'w') as f:
330
f.write('Modification to file FILE_B.')
331
with open('FILE_C', 'w') as f:
332
f.write('Modification to file FILE_C.')
299
333
unlink('FILE_E') # FILE_E will be versioned but missing
300
open('FILE_Q', 'w').write('FILE_Q is added but not committed.')
334
with open('FILE_Q', 'w') as f:
335
f.write('FILE_Q is added but not committed.')
301
336
wt.add('FILE_Q') # FILE_Q will be added but not committed
302
337
open('UNVERSIONED_BUT_EXISTING', 'w')
330
365
# Okay, everything's looking good with the existent files.
331
366
# Let's see what happens when we throw in non-existent files.
333
# bzr st [--short] NONEXISTENT '
368
# brz st [--short] NONEXISTENT '
338
373
out, err = self.run_bzr('status NONEXISTENT', retcode=3)
339
374
self.assertEqual(expected, out.splitlines(True))
340
375
self.assertContainsRe(err,
341
376
r'.*ERROR: Path\(s\) do not exist: '
346
381
out, err = self.run_bzr('status --short NONEXISTENT', retcode=3)
347
382
self.assertContainsRe(err,
348
383
r'.*ERROR: Path\(s\) do not exist: '
351
386
def test_status_nonexistent_file_with_others(self):
352
# bzr st [--short] NONEXISTENT ...others..
387
# brz st [--short] NONEXISTENT ...others..
353
388
wt = self._prepare_nonexistent()
363
398
out, err = self.run_bzr('status NONEXISTENT '
364
399
'FILE_A FILE_B FILE_C FILE_D FILE_E',
384
419
def test_status_multiple_nonexistent_files(self):
385
# bzr st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
420
# brz st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
386
421
wt = self._prepare_nonexistent()
394
' ANOTHER_NONEXISTENT\n',
429
' ANOTHER_NONEXISTENT\n',
397
432
out, err = self.run_bzr('status NONEXISTENT '
398
433
'FILE_A FILE_B ANOTHER_NONEXISTENT '
399
434
'FILE_C FILE_D FILE_E', retcode=3)
417
452
'ANOTHER_NONEXISTENT NONEXISTENT.*')
419
454
def test_status_nonexistent_file_with_unversioned(self):
420
# bzr st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
455
# brz st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
421
456
wt = self._prepare_nonexistent()
431
' UNVERSIONED_BUT_EXISTING\n',
466
' UNVERSIONED_BUT_EXISTING\n',
435
470
out, err = self.run_bzr('status NONEXISTENT '
436
471
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
437
472
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
439
474
self.assertContainsRe(err,
440
475
r'.*ERROR: Path\(s\) do not exist: '
444
'? UNVERSIONED_BUT_EXISTING\n',
479
'? UNVERSIONED_BUT_EXISTING\n',
450
485
out, err = self.run_bzr('status --short NONEXISTENT '
451
486
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
452
487
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
453
self.assertEqual(expected, out.splitlines(True))
488
actual = out.splitlines(True)
490
self.assertEqual(expected, actual)
454
491
self.assertContainsRe(err,
455
492
r'.*ERROR: Path\(s\) do not exist: '
458
495
def test_status_out_of_date(self):
459
496
"""Simulate status of out-of-date tree after remote push"""
460
497
tree = self.make_branch_and_tree('.')
461
self.build_tree_contents([('a', 'foo\n')])
498
self.build_tree_contents([('a', b'foo\n')])
499
with tree.lock_write():
465
501
tree.commit('add test file')
466
502
# simulate what happens after a remote push
467
tree.set_last_revision("0")
469
# before run another commands we should unlock tree
503
tree.set_last_revision(b"0")
471
504
out, err = self.run_bzr('status')
472
self.assertEqual("working tree is out of date, run 'bzr update'\n",
505
self.assertEqual("working tree is out of date, run 'brz update'\n",
475
508
def test_status_on_ignored(self):
483
516
result = self.run_bzr('status')[0]
484
517
self.assertContainsRe(result, "unknown:\n test1.c\n")
485
518
short_result = self.run_bzr('status --short')[0]
486
self.assertContainsRe(short_result, "\? test1.c\n")
519
self.assertContainsRe(short_result, "\\? test1.c\n")
488
521
result = self.run_bzr('status test1.c')[0]
489
522
self.assertContainsRe(result, "unknown:\n test1.c\n")
490
523
short_result = self.run_bzr('status --short test1.c')[0]
491
self.assertContainsRe(short_result, "\? test1.c\n")
524
self.assertContainsRe(short_result, "\\? test1.c\n")
493
526
result = self.run_bzr('status test1.c~')[0]
494
527
self.assertContainsRe(result, "ignored:\n test1.c~\n")
501
534
self.assertContainsRe(short_result, "I test1.c~\nI test2.c~\n")
503
536
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")
537
self.assertContainsRe(
538
result, "unknown:\n test1.c\nignored:\n test1.c~\n test2.c~\n")
539
short_result = self.run_bzr(
540
'status --short test1.c test1.c~ test2.c~')[0]
541
self.assertContainsRe(
542
short_result, "\\? test1.c\nI test1.c~\nI test2.c~\n")
508
544
def test_status_write_lock(self):
509
545
"""Test that status works without fetching history and
515
551
wt = self.make_branch_and_tree('branch1')
517
553
wt.commit('Empty commit 1')
518
wt2 = b.bzrdir.sprout('branch2').open_workingtree()
554
wt2 = b.controldir.sprout('branch2').open_workingtree()
519
555
wt2.commit('Empty commit 2')
520
556
out, err = self.run_bzr('status branch1 -rbranch:branch2')
521
557
self.assertEqual('', out)
559
def test_status_with_shelves(self):
560
"""Ensure that _show_shelve_summary handler works.
562
wt = self.make_branch_and_tree('.')
563
self.build_tree(['hello.c'])
565
self.run_bzr(['shelve', '--all', '-m', 'foo'])
566
self.build_tree(['bye.c'])
571
'1 shelf exists. See "brz shelve --list" for details.\n',
574
self.run_bzr(['shelve', '--all', '-m', 'bar'])
575
self.build_tree(['eggs.c', 'spam.c'])
582
'2 shelves exist. See "brz shelve --list" for details.\n',
590
specific_files=['spam.c'])
524
593
class CheckoutStatus(BranchStatus):
559
627
self.build_tree(['world.txt'])
560
628
result = self.run_bzr("status -r 0")[0]
561
self.assertContainsRe(result, "added:\n hello.txt\n" \
629
self.assertContainsRe(result, "added:\n hello.txt\n"
562
630
"unknown:\n world.txt\n")
563
631
result2 = self.run_bzr("status -r 0..")[0]
564
self.assertEquals(result2, result)
632
self.assertEqual(result2, result)
566
634
def test_status_short(self):
567
635
tree = self.make_branch_and_tree('.')
579
647
self.assertContainsRe(result, "[+]N hello.txt\n")
581
649
self.build_tree(['world.txt'])
582
result = self.run_bzr("status --short -r 0")[0]
583
self.assertContainsRe(result, "[+]N hello.txt\n" \
650
result = self.run_bzr("status -S -r 0")[0]
651
self.assertContainsRe(result, "[+]N hello.txt\n"
584
652
"[?] world.txt\n")
585
result2 = self.run_bzr("status --short -r 0..")[0]
586
self.assertEquals(result2, result)
653
result2 = self.run_bzr("status -S -r 0..")[0]
654
self.assertEqual(result2, result)
588
656
def test_status_versioned(self):
589
657
tree = self.make_branch_and_tree('.')
644
712
tree.commit('added file')
646
714
self.build_tree(['file/'])
647
self.assertStatusContains('kind changed:\n file \(file => directory\)')
715
self.assertStatusContains(
716
'kind changed:\n file \\(file => directory\\)')
648
717
tree.rename_one('file', 'directory')
649
self.assertStatusContains('renamed:\n file/ => directory/\n' \
718
self.assertStatusContains('renamed:\n file => directory/\n'
650
719
'modified:\n directory/\n')
651
720
rmdir('directory')
652
721
self.assertStatusContains('removed:\n file\n')
676
745
self.build_tree(['a/a'])
678
747
a_tree.commit('a')
679
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
748
b_tree = a_tree.controldir.sprout('b').open_workingtree()
680
749
self.build_tree(['b/b'])
682
751
b_tree.commit('b')
684
753
self.run_bzr('merge ../b', working_dir='a')
685
754
out, err = self.run_bzr('status --no-pending', working_dir='a')
686
self.assertEquals(out, "added:\n b\n")
755
self.assertEqual(out, "added:\n b\n")
688
757
def test_pending_specific_files(self):
689
758
"""With a specific file list, pending merges are not shown."""
690
759
tree = self.make_branch_and_tree('tree')
691
self.build_tree_contents([('tree/a', 'content of a\n')])
760
self.build_tree_contents([('tree/a', b'content of a\n')])
693
762
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')])
763
alt = tree.controldir.sprout('alt').open_workingtree()
764
self.build_tree_contents([('alt/a', b'content of a\nfrom alt\n')])
696
765
alt_id = alt.commit('alt')
697
766
tree.merge_from_branch(alt.branch)
698
767
output = self.make_utf8_encoded_stringio()
699
768
show_tree_status(tree, to_file=output)
700
self.assertContainsRe(output.getvalue(), 'pending merge')
769
self.assertContainsRe(output.getvalue(), b'pending merge')
701
770
out, err = self.run_bzr('status tree/a')
702
771
self.assertNotContainsRe(out, 'pending merge')
705
774
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
776
def make_uncommitted_tree(self):
718
777
"""Build a branch with uncommitted unicode named changes in the cwd."""
719
778
working_tree = self.make_branch_and_tree(u'.')
720
779
filename = u'hell\u00d8'
722
self.build_tree_contents([(filename, 'contents of hello')])
781
self.build_tree_contents([(filename, b'contents of hello')])
723
782
except UnicodeEncodeError:
724
783
raise TestSkipped("can't build unicode working tree in "
725
"filesystem encoding %s" % sys.getfilesystemencoding())
784
"filesystem encoding %s" % sys.getfilesystemencoding())
726
785
working_tree.add(filename)
727
786
return working_tree
729
788
def test_stdout_ascii(self):
730
sys.stdout = StringIO()
731
osutils._cached_user_encoding = 'ascii'
789
self.overrideAttr(osutils, '_cached_user_encoding', 'ascii')
732
790
working_tree = self.make_uncommitted_tree()
733
791
stdout, stderr = self.run_bzr("status")
735
self.assertEquals(stdout, """\
793
self.assertEqual(stdout, """\
740
798
def test_stdout_latin1(self):
741
sys.stdout = StringIO()
742
osutils._cached_user_encoding = 'latin-1'
799
self.overrideAttr(osutils, '_cached_user_encoding', 'latin-1')
743
800
working_tree = self.make_uncommitted_tree()
744
801
stdout, stderr = self.run_bzr('status')
746
self.assertEquals(stdout, u"""\
749
""".encode('latin-1'))
807
self.assertEqual(stdout, expected)