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 (
44
from ...status import show_tree_status
45
from .. import TestCaseWithTransport, TestSkipped
46
from ...workingtree import WorkingTree
45
49
class BranchStatus(TestCaseWithTransport):
47
def assertStatus(self, expected_lines, working_tree,
52
super(BranchStatus, self).setUp()
53
# As TestCase.setUp clears all hooks, we install this default
54
# post_status hook handler for the test.
55
status.hooks.install_named_hook('post_status',
56
status._show_shelve_summary,
59
def assertStatus(self, expected_lines, working_tree, specific_files=None,
48
60
revision=None, short=False, pending=True, verbose=False):
49
61
"""Run status in working_tree and look for output.
51
63
:param expected_lines: The lines to look for.
52
64
:param working_tree: The tree to run status in.
54
output_string = self.status_string(working_tree, revision, short,
66
output_string = self.status_string(working_tree, specific_files, revision, short,
56
68
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')
70
def status_string(self, wt, specific_files=None, revision=None,
71
short=False, pending=True, verbose=False):
72
uio = self.make_utf8_encoded_stringio()
73
show_tree_status(wt, specific_files=specific_files, to_file=uio,
74
revision=revision, short=short, show_pending=pending,
76
return uio.getvalue().decode('utf-8')
68
78
def test_branch_status(self):
69
79
"""Test basic branch status"""
218
234
self.assertStatus([
221
238
'? directory/hello.c\n'
226
243
self.assertRaises(errors.PathsDoNotExist,
227
244
show_tree_status,
228
wt, specific_files=['bye.c','test.c','absent.c'],
245
wt, specific_files=['bye.c', 'test.c', 'absent.c'],
232
249
show_tree_status(wt, specific_files=['directory'], to_file=tof)
234
self.assertEquals(tof.readlines(),
251
self.assertEqual(tof.readlines(),
236
253
' directory/hello.c\n'
239
256
show_tree_status(wt, specific_files=['directory'], to_file=tof,
242
self.assertEquals(tof.readlines(), ['? directory/hello.c\n'])
259
self.assertEqual(tof.readlines(), ['? directory/hello.c\n'])
245
262
show_tree_status(wt, specific_files=['dir2'], to_file=tof)
247
self.assertEquals(tof.readlines(),
264
self.assertEqual(tof.readlines(),
252
269
show_tree_status(wt, specific_files=['dir2'], to_file=tof, short=True)
254
self.assertEquals(tof.readlines(), ['? dir2/\n'])
271
self.assertEqual(tof.readlines(), ['? dir2/\n'])
257
274
revs = [RevisionSpec.from_string('0'), RevisionSpec.from_string('1')]
258
275
show_tree_status(wt, specific_files=['test.c'], to_file=tof,
259
276
short=True, revision=revs)
261
self.assertEquals(tof.readlines(), ['+N test.c\n'])
278
self.assertEqual(tof.readlines(), ['+N test.c\n'])
281
show_tree_status(wt, specific_files=['missing.c'], to_file=tof)
283
self.assertEqual(tof.readlines(),
288
show_tree_status(wt, specific_files=['missing.c'], to_file=tof,
291
self.assertEqual(tof.readlines(),
263
294
def test_specific_files_conflicts(self):
264
295
tree = self.make_branch_and_tree('.')
338
369
out, err = self.run_bzr('status NONEXISTENT', retcode=3)
339
370
self.assertEqual(expected, out.splitlines(True))
340
371
self.assertContainsRe(err,
341
r'.*ERROR: Path\(s\) do not exist: '
372
br'.*ERROR: Path\(s\) do not exist: '
344
375
'X: NONEXISTENT\n',
346
377
out, err = self.run_bzr('status --short NONEXISTENT', retcode=3)
347
378
self.assertContainsRe(err,
348
r'.*ERROR: Path\(s\) do not exist: '
379
br'.*ERROR: Path\(s\) do not exist: '
351
382
def test_status_nonexistent_file_with_others(self):
352
# bzr st [--short] NONEXISTENT ...others..
383
# brz st [--short] NONEXISTENT ...others..
353
384
wt = self._prepare_nonexistent()
363
394
out, err = self.run_bzr('status NONEXISTENT '
364
395
'FILE_A FILE_B FILE_C FILE_D FILE_E',
366
397
self.assertEqual(expected, out.splitlines(True))
367
398
self.assertContainsRe(err,
368
r'.*ERROR: Path\(s\) do not exist: '
399
br'.*ERROR: Path\(s\) do not exist: '
376
407
out, err = self.run_bzr('status --short NONEXISTENT '
377
408
'FILE_A FILE_B FILE_C FILE_D FILE_E',
379
410
self.assertEqual(expected, out.splitlines(True))
380
411
self.assertContainsRe(err,
381
r'.*ERROR: Path\(s\) do not exist: '
412
br'.*ERROR: Path\(s\) do not exist: '
384
415
def test_status_multiple_nonexistent_files(self):
385
# bzr st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
416
# brz st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
386
417
wt = self._prepare_nonexistent()
394
' ANOTHER_NONEXISTENT\n',
425
b' ANOTHER_NONEXISTENT\n',
397
428
out, err = self.run_bzr('status NONEXISTENT '
398
429
'FILE_A FILE_B ANOTHER_NONEXISTENT '
399
430
'FILE_C FILE_D FILE_E', retcode=3)
400
431
self.assertEqual(expected, out.splitlines(True))
401
432
self.assertContainsRe(err,
402
r'.*ERROR: Path\(s\) do not exist: '
403
'ANOTHER_NONEXISTENT NONEXISTENT.*')
433
br'.*ERROR: Path\(s\) do not exist: '
434
b'ANOTHER_NONEXISTENT NONEXISTENT.*')
408
'X ANOTHER_NONEXISTENT\n',
439
b'X ANOTHER_NONEXISTENT\n',
411
442
out, err = self.run_bzr('status --short NONEXISTENT '
412
443
'FILE_A FILE_B ANOTHER_NONEXISTENT '
413
444
'FILE_C FILE_D FILE_E', retcode=3)
414
445
self.assertEqual(expected, out.splitlines(True))
415
446
self.assertContainsRe(err,
416
r'.*ERROR: Path\(s\) do not exist: '
417
'ANOTHER_NONEXISTENT NONEXISTENT.*')
447
br'.*ERROR: Path\(s\) do not exist: '
448
b'ANOTHER_NONEXISTENT NONEXISTENT.*')
419
450
def test_status_nonexistent_file_with_unversioned(self):
420
# bzr st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
451
# brz st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
421
452
wt = self._prepare_nonexistent()
431
' UNVERSIONED_BUT_EXISTING\n',
462
b' UNVERSIONED_BUT_EXISTING\n',
435
466
out, err = self.run_bzr('status NONEXISTENT '
436
467
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
437
468
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
438
469
self.assertEqual(expected, out.splitlines(True))
439
470
self.assertContainsRe(err,
440
r'.*ERROR: Path\(s\) do not exist: '
444
'? UNVERSIONED_BUT_EXISTING\n',
471
br'.*ERROR: Path\(s\) do not exist: '
475
b'? UNVERSIONED_BUT_EXISTING\n',
450
481
out, err = self.run_bzr('status --short NONEXISTENT '
451
482
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
452
483
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
453
self.assertEqual(expected, out.splitlines(True))
484
actual = out.splitlines(True)
486
self.assertEqual(expected, actual)
454
487
self.assertContainsRe(err,
455
r'.*ERROR: Path\(s\) do not exist: '
488
br'.*ERROR: Path\(s\) do not exist: '
458
491
def test_status_out_of_date(self):
459
492
"""Simulate status of out-of-date tree after remote push"""
460
493
tree = self.make_branch_and_tree('.')
461
self.build_tree_contents([('a', 'foo\n')])
494
self.build_tree_contents([('a', b'foo\n')])
462
495
tree.lock_write()
465
498
tree.commit('add test file')
466
499
# simulate what happens after a remote push
467
tree.set_last_revision("0")
500
tree.set_last_revision(b"0")
469
502
# before run another commands we should unlock tree
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):
482
515
self.build_tree(['test1.c', 'test1.c~', 'test2.c~'])
483
516
result = self.run_bzr('status')[0]
484
self.assertContainsRe(result, "unknown:\n test1.c\n")
517
self.assertContainsRe(result, b"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, b"\\? test1.c\n")
488
521
result = self.run_bzr('status test1.c')[0]
489
self.assertContainsRe(result, "unknown:\n test1.c\n")
522
self.assertContainsRe(result, b"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, b"\\? test1.c\n")
493
526
result = self.run_bzr('status test1.c~')[0]
494
self.assertContainsRe(result, "ignored:\n test1.c~\n")
527
self.assertContainsRe(result, b"ignored:\n test1.c~\n")
495
528
short_result = self.run_bzr('status --short test1.c~')[0]
496
self.assertContainsRe(short_result, "I test1.c~\n")
529
self.assertContainsRe(short_result, b"I test1.c~\n")
498
531
result = self.run_bzr('status test1.c~ test2.c~')[0]
499
self.assertContainsRe(result, "ignored:\n test1.c~\n test2.c~\n")
532
self.assertContainsRe(result, b"ignored:\n test1.c~\n test2.c~\n")
500
533
short_result = self.run_bzr('status --short test1.c~ test2.c~')[0]
501
self.assertContainsRe(short_result, "I test1.c~\nI test2.c~\n")
534
self.assertContainsRe(short_result, b"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")
537
self.assertContainsRe(result, b"unknown:\n test1.c\nignored:\n test1.c~\n test2.c~\n")
505
538
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")
539
self.assertContainsRe(short_result, b"\\? test1.c\nI test1.c~\nI test2.c~\n")
508
541
def test_status_write_lock(self):
509
542
"""Test that status works without fetching history and
515
548
wt = self.make_branch_and_tree('branch1')
517
550
wt.commit('Empty commit 1')
518
wt2 = b.bzrdir.sprout('branch2').open_workingtree()
551
wt2 = b.controldir.sprout('branch2').open_workingtree()
519
552
wt2.commit('Empty commit 2')
520
553
out, err = self.run_bzr('status branch1 -rbranch:branch2')
521
self.assertEqual('', out)
554
self.assertEqual(b'', out)
556
def test_status_with_shelves(self):
557
"""Ensure that _show_shelve_summary handler works.
559
wt = self.make_branch_and_tree('.')
560
self.build_tree(['hello.c'])
562
self.run_bzr(['shelve', '--all', '-m', 'foo'])
563
self.build_tree(['bye.c'])
568
b'1 shelf exists. See "brz shelve --list" for details.\n',
571
self.run_bzr(['shelve', '--all', '-m', 'bar'])
572
self.build_tree(['eggs.c', 'spam.c'])
579
b'2 shelves exist. See "brz shelve --list" for details.\n',
587
specific_files=['spam.c'])
524
590
class CheckoutStatus(BranchStatus):
544
609
self.build_tree(['hello.txt'])
545
610
result = self.run_bzr("status")[0]
546
self.assertContainsRe(result, "unknown:\n hello.txt\n")
611
self.assertContainsRe(result, b"unknown:\n hello.txt\n")
548
613
tree.add("hello.txt")
549
614
result = self.run_bzr("status")[0]
550
self.assertContainsRe(result, "added:\n hello.txt\n")
615
self.assertContainsRe(result, b"added:\n hello.txt\n")
552
617
tree.commit(message="added")
553
618
result = self.run_bzr("status -r 0..1")[0]
554
self.assertContainsRe(result, "added:\n hello.txt\n")
619
self.assertContainsRe(result, b"added:\n hello.txt\n")
556
621
result = self.run_bzr("status -c 1")[0]
557
self.assertContainsRe(result, "added:\n hello.txt\n")
622
self.assertContainsRe(result, b"added:\n hello.txt\n")
559
624
self.build_tree(['world.txt'])
560
625
result = self.run_bzr("status -r 0")[0]
561
self.assertContainsRe(result, "added:\n hello.txt\n" \
562
"unknown:\n world.txt\n")
626
self.assertContainsRe(result, b"added:\n hello.txt\n" \
627
b"unknown:\n world.txt\n")
563
628
result2 = self.run_bzr("status -r 0..")[0]
564
self.assertEquals(result2, result)
629
self.assertEqual(result2, result)
566
631
def test_status_short(self):
567
632
tree = self.make_branch_and_tree('.')
569
634
self.build_tree(['hello.txt'])
570
635
result = self.run_bzr("status --short")[0]
571
self.assertContainsRe(result, "[?] hello.txt\n")
636
self.assertContainsRe(result, b"[?] hello.txt\n")
573
638
tree.add("hello.txt")
574
639
result = self.run_bzr("status --short")[0]
575
self.assertContainsRe(result, "[+]N hello.txt\n")
640
self.assertContainsRe(result, b"[+]N hello.txt\n")
577
642
tree.commit(message="added")
578
643
result = self.run_bzr("status --short -r 0..1")[0]
579
self.assertContainsRe(result, "[+]N hello.txt\n")
644
self.assertContainsRe(result, b"[+]N hello.txt\n")
581
646
self.build_tree(['world.txt'])
582
result = self.run_bzr("status --short -r 0")[0]
583
self.assertContainsRe(result, "[+]N hello.txt\n" \
585
result2 = self.run_bzr("status --short -r 0..")[0]
586
self.assertEquals(result2, result)
647
result = self.run_bzr("status -S -r 0")[0]
648
self.assertContainsRe(result, b"[+]N hello.txt\n" \
650
result2 = self.run_bzr("status -S -r 0..")[0]
651
self.assertEqual(result2, result)
588
653
def test_status_versioned(self):
589
654
tree = self.make_branch_and_tree('.')
591
656
self.build_tree(['hello.txt'])
592
657
result = self.run_bzr("status --versioned")[0]
593
self.assertNotContainsRe(result, "unknown:\n hello.txt\n")
658
self.assertNotContainsRe(result, b"unknown:\n hello.txt\n")
595
660
tree.add("hello.txt")
596
661
result = self.run_bzr("status --versioned")[0]
597
self.assertContainsRe(result, "added:\n hello.txt\n")
662
self.assertContainsRe(result, b"added:\n hello.txt\n")
599
664
tree.commit("added")
600
665
result = self.run_bzr("status --versioned -r 0..1")[0]
601
self.assertContainsRe(result, "added:\n hello.txt\n")
666
self.assertContainsRe(result, b"added:\n hello.txt\n")
603
668
self.build_tree(['world.txt'])
604
669
result = self.run_bzr("status --versioned -r 0")[0]
605
self.assertContainsRe(result, "added:\n hello.txt\n")
606
self.assertNotContainsRe(result, "unknown:\n world.txt\n")
670
self.assertContainsRe(result, b"added:\n hello.txt\n")
671
self.assertNotContainsRe(result, b"unknown:\n world.txt\n")
607
672
result2 = self.run_bzr("status --versioned -r 0..")[0]
608
self.assertEquals(result2, result)
673
self.assertEqual(result2, result)
610
675
def test_status_SV(self):
611
676
tree = self.make_branch_and_tree('.')
613
678
self.build_tree(['hello.txt'])
614
679
result = self.run_bzr("status -SV")[0]
615
self.assertNotContainsRe(result, "hello.txt")
680
self.assertNotContainsRe(result, b"hello.txt")
617
682
tree.add("hello.txt")
618
683
result = self.run_bzr("status -SV")[0]
619
self.assertContainsRe(result, "[+]N hello.txt\n")
684
self.assertContainsRe(result, b"[+]N hello.txt\n")
621
686
tree.commit(message="added")
622
687
result = self.run_bzr("status -SV -r 0..1")[0]
623
self.assertContainsRe(result, "[+]N hello.txt\n")
688
self.assertContainsRe(result, b"[+]N hello.txt\n")
625
690
self.build_tree(['world.txt'])
626
691
result = self.run_bzr("status -SV -r 0")[0]
627
self.assertContainsRe(result, "[+]N hello.txt\n")
692
self.assertContainsRe(result, b"[+]N hello.txt\n")
629
694
result2 = self.run_bzr("status -SV -r 0..")[0]
630
self.assertEquals(result2, result)
695
self.assertEqual(result2, result)
632
697
def assertStatusContains(self, pattern, short=False):
633
698
"""Run status, and assert it contains the given pattern"""
670
735
def test_status_illegal_revision_specifiers(self):
671
736
out, err = self.run_bzr('status -r 1..23..123', retcode=3)
672
self.assertContainsRe(err, 'one or two revision specifiers')
737
self.assertContainsRe(err, b'one or two revision specifiers')
674
739
def test_status_no_pending(self):
675
740
a_tree = self.make_branch_and_tree('a')
676
741
self.build_tree(['a/a'])
678
743
a_tree.commit('a')
679
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
744
b_tree = a_tree.controldir.sprout('b').open_workingtree()
680
745
self.build_tree(['b/b'])
682
747
b_tree.commit('b')
684
749
self.run_bzr('merge ../b', working_dir='a')
685
750
out, err = self.run_bzr('status --no-pending', working_dir='a')
686
self.assertEquals(out, "added:\n b\n")
751
self.assertEqual(out, "added:\n b\n")
688
753
def test_pending_specific_files(self):
689
754
"""With a specific file list, pending merges are not shown."""
690
755
tree = self.make_branch_and_tree('tree')
691
self.build_tree_contents([('tree/a', 'content of a\n')])
756
self.build_tree_contents([('tree/a', b'content of a\n')])
693
758
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')])
759
alt = tree.controldir.sprout('alt').open_workingtree()
760
self.build_tree_contents([('alt/a', b'content of a\nfrom alt\n')])
696
761
alt_id = alt.commit('alt')
697
762
tree.merge_from_branch(alt.branch)
698
763
output = self.make_utf8_encoded_stringio()
699
764
show_tree_status(tree, to_file=output)
700
self.assertContainsRe(output.getvalue(), 'pending merge')
765
self.assertContainsRe(output.getvalue(), b'pending merge')
701
766
out, err = self.run_bzr('status tree/a')
702
self.assertNotContainsRe(out, 'pending merge')
767
self.assertNotContainsRe(out, b'pending merge')
705
770
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
772
def make_uncommitted_tree(self):
718
773
"""Build a branch with uncommitted unicode named changes in the cwd."""
719
774
working_tree = self.make_branch_and_tree(u'.')
720
775
filename = u'hell\u00d8'
722
self.build_tree_contents([(filename, 'contents of hello')])
777
self.build_tree_contents([(filename, b'contents of hello')])
723
778
except UnicodeEncodeError:
724
779
raise TestSkipped("can't build unicode working tree in "
725
780
"filesystem encoding %s" % sys.getfilesystemencoding())