22
22
interface later, they will be non blackbox tests.
25
from cStringIO import StringIO
30
27
from os import mkdir, chdir, rmdir, unlink
29
from tempfile import TemporaryFile
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
39
from brzlib.osutils import pathjoin
40
from brzlib.revisionspec import RevisionSpec
41
from brzlib.status import show_tree_status
42
from brzlib.tests import TestCaseWithTransport, TestSkipped
43
from brzlib.workingtree import WorkingTree
50
46
class BranchStatus(TestCaseWithTransport):
54
50
# As TestCase.setUp clears all hooks, we install this default
55
51
# post_status hook handler for the test.
56
52
status.hooks.install_named_hook('post_status',
57
status._show_shelve_summary,
53
status._show_shelve_summary,
60
56
def assertStatus(self, expected_lines, working_tree, specific_files=None,
61
revision=None, short=False, pending=True, verbose=False):
57
revision=None, short=False, pending=True, verbose=False):
62
58
"""Run status in working_tree and look for output.
64
60
:param expected_lines: The lines to look for.
65
61
:param working_tree: The tree to run status in.
67
63
output_string = self.status_string(working_tree, specific_files, revision, short,
69
65
self.assertEqual(expected_lines, output_string.splitlines(True))
71
67
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
short=False, pending=True, verbose=False):
69
# use a real file rather than StringIO because it doesn't handle
71
tof = codecs.getwriter('utf-8')(TemporaryFile())
72
show_tree_status(wt, specific_files=specific_files, to_file=tof,
73
revision=revision, short=short, show_pending=pending,
76
return tof.read().decode('utf-8')
79
78
def test_branch_status(self):
80
79
"""Test basic branch status"""
89
88
self.build_tree(['hello.c', 'bye.c'])
90
89
self.assertStatus([
96
95
self.assertStatus([
102
101
# add a commit to allow showing pending merges.
103
102
wt.commit('create a parent to allow testing merge output')
105
wt.add_parent_tree_id(b'pending@pending-0-0')
104
wt.add_parent_tree_id('pending@pending-0-0')
106
105
self.assertStatus([
110
'pending merge tips: (use -v to see all merge revisions)\n',
111
' (ghost) pending@pending-0-0\n',
109
'pending merge tips: (use -v to see all merge revisions)\n',
110
' (ghost) pending@pending-0-0\n',
114
113
self.assertStatus([
119
' (ghost) pending@pending-0-0\n',
118
' (ghost) pending@pending-0-0\n',
121
120
wt, verbose=True)
122
121
self.assertStatus([
125
'P (ghost) pending@pending-0-0\n',
124
'P (ghost) pending@pending-0-0\n',
128
127
self.assertStatus([
133
132
wt, pending=False)
134
133
self.assertStatus([
138
137
wt, short=True, pending=False)
174
173
wt = self.make_branch_and_tree('branch')
176
175
wt.commit("Empty commit 1")
177
b_2_dir = b.controldir.sprout('./copy')
176
b_2_dir = b.bzrdir.sprout('./copy')
178
177
b_2 = b_2_dir.open_branch()
179
178
wt2 = b_2_dir.open_workingtree()
180
179
wt.commit(u"\N{TIBETAN DIGIT TWO} Empty commit 2")
184
183
self.assertEndsWith(message, "Empty commit 2\n")
185
184
wt2.commit("merged")
186
185
# must be long to make sure we see elipsis at the end
187
wt.commit("Empty commit 3 "
188
+ "blah blah blah blah " * 100)
186
wt.commit("Empty commit 3 " +
187
"blah blah blah blah " * 100)
189
188
wt2.merge_from_branch(wt.branch)
190
189
message = self.status_string(wt2, verbose=True)
191
190
self.assertStartsWith(message, "pending merges:\n")
199
198
wt.commit('commit .bzrignore')
200
199
self.build_tree(['foo.c', 'foo.c~'])
201
200
self.assertStatus([
206
205
self.assertStatus([
211
210
def test_tree_status_specific_files(self):
212
211
"""Tests branch status with given specific files"""
213
212
wt = self.make_branch_and_tree('.')
216
self.build_tree(['directory/', 'directory/hello.c',
217
'bye.c', 'test.c', 'dir2/',
215
self.build_tree(['directory/','directory/hello.c',
216
'bye.c','test.c','dir2/',
219
218
wt.add('directory')
223
222
unlink('missing.c')
225
224
self.assertStatus([
231
' directory/hello.c\n'
230
' directory/hello.c\n'
235
234
self.assertStatus([
238
'? directory/hello.c\n',
238
'? directory/hello.c\n'
244
243
self.assertRaises(errors.PathsDoNotExist,
245
244
show_tree_status,
246
wt, specific_files=['bye.c', 'test.c', 'absent.c'],
245
wt, specific_files=['bye.c','test.c','absent.c'],
250
249
show_tree_status(wt, specific_files=['directory'], to_file=tof)
252
251
self.assertEqual(tof.readlines(),
254
' directory/hello.c\n'
253
' directory/hello.c\n'
257
256
show_tree_status(wt, specific_files=['directory'], to_file=tof,
263
262
show_tree_status(wt, specific_files=['dir2'], to_file=tof)
265
264
self.assertEqual(tof.readlines(),
270
269
show_tree_status(wt, specific_files=['dir2'], to_file=tof, short=True)
282
281
show_tree_status(wt, specific_files=['missing.c'], to_file=tof)
284
283
self.assertEqual(tof.readlines(),
289
288
show_tree_status(wt, specific_files=['missing.c'], to_file=tof,
292
291
self.assertEqual(tof.readlines(),
295
294
def test_specific_files_conflicts(self):
296
295
tree = self.make_branch_and_tree('.')
299
298
tree.commit('added dir2')
300
299
tree.set_conflicts(conflicts.ConflictList(
301
300
[conflicts.ContentsConflict('foo')]))
303
302
show_tree_status(tree, specific_files=['dir2'], to_file=tof)
304
self.assertEqualDiff(b'', tof.getvalue())
303
self.assertEqualDiff('', tof.getvalue())
305
304
tree.set_conflicts(conflicts.ConflictList(
306
305
[conflicts.ContentsConflict('dir2')]))
328
327
wt.commit('Create five empty files.')
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.')
328
with open('FILE_B', 'w') as f: f.write('Modification to file FILE_B.')
329
with open('FILE_C', 'w') as f: f.write('Modification to file FILE_C.')
333
330
unlink('FILE_E') # FILE_E will be versioned but missing
334
with open('FILE_Q', 'w') as f:
335
f.write('FILE_Q is added but not committed.')
331
with open('FILE_Q', 'w') as f: f.write('FILE_Q is added but not committed.')
336
332
wt.add('FILE_Q') # FILE_Q will be added but not committed
337
333
open('UNVERSIONED_BUT_EXISTING', 'w')
365
361
# Okay, everything's looking good with the existent files.
366
362
# Let's see what happens when we throw in non-existent files.
368
# brz st [--short] NONEXISTENT '
364
# bzr st [--short] NONEXISTENT '
373
369
out, err = self.run_bzr('status NONEXISTENT', retcode=3)
374
370
self.assertEqual(expected, out.splitlines(True))
375
371
self.assertContainsRe(err,
376
372
r'.*ERROR: Path\(s\) do not exist: '
381
377
out, err = self.run_bzr('status --short NONEXISTENT', retcode=3)
382
378
self.assertContainsRe(err,
383
379
r'.*ERROR: Path\(s\) do not exist: '
386
382
def test_status_nonexistent_file_with_others(self):
387
# brz st [--short] NONEXISTENT ...others..
383
# bzr st [--short] NONEXISTENT ...others..
388
384
wt = self._prepare_nonexistent()
398
394
out, err = self.run_bzr('status NONEXISTENT '
399
395
'FILE_A FILE_B FILE_C FILE_D FILE_E',
419
415
def test_status_multiple_nonexistent_files(self):
420
# brz st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
416
# bzr st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
421
417
wt = self._prepare_nonexistent()
429
' ANOTHER_NONEXISTENT\n',
425
' ANOTHER_NONEXISTENT\n',
432
428
out, err = self.run_bzr('status NONEXISTENT '
433
429
'FILE_A FILE_B ANOTHER_NONEXISTENT '
434
430
'FILE_C FILE_D FILE_E', retcode=3)
437
433
r'.*ERROR: Path\(s\) do not exist: '
438
434
'ANOTHER_NONEXISTENT NONEXISTENT.*')
443
'X ANOTHER_NONEXISTENT\n',
439
'X ANOTHER_NONEXISTENT\n',
446
442
out, err = self.run_bzr('status --short NONEXISTENT '
447
443
'FILE_A FILE_B ANOTHER_NONEXISTENT '
448
444
'FILE_C FILE_D FILE_E', retcode=3)
452
448
'ANOTHER_NONEXISTENT NONEXISTENT.*')
454
450
def test_status_nonexistent_file_with_unversioned(self):
455
# brz st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
451
# bzr st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
456
452
wt = self._prepare_nonexistent()
466
' UNVERSIONED_BUT_EXISTING\n',
462
' UNVERSIONED_BUT_EXISTING\n',
470
466
out, err = self.run_bzr('status NONEXISTENT '
471
467
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
472
468
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
474
470
self.assertContainsRe(err,
475
471
r'.*ERROR: Path\(s\) do not exist: '
479
'? UNVERSIONED_BUT_EXISTING\n',
475
'? UNVERSIONED_BUT_EXISTING\n',
485
482
out, err = self.run_bzr('status --short NONEXISTENT '
486
483
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
487
484
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
495
492
def test_status_out_of_date(self):
496
493
"""Simulate status of out-of-date tree after remote push"""
497
494
tree = self.make_branch_and_tree('.')
498
self.build_tree_contents([('a', b'foo\n')])
499
with tree.lock_write():
495
self.build_tree_contents([('a', 'foo\n')])
501
499
tree.commit('add test file')
502
500
# simulate what happens after a remote push
503
tree.set_last_revision(b"0")
501
tree.set_last_revision("0")
503
# before run another commands we should unlock tree
504
505
out, err = self.run_bzr('status')
505
self.assertEqual("working tree is out of date, run 'brz update'\n",
506
self.assertEqual("working tree is out of date, run 'bzr update'\n",
508
509
def test_status_on_ignored(self):
516
517
result = self.run_bzr('status')[0]
517
518
self.assertContainsRe(result, "unknown:\n test1.c\n")
518
519
short_result = self.run_bzr('status --short')[0]
519
self.assertContainsRe(short_result, "\\? test1.c\n")
520
self.assertContainsRe(short_result, "\? test1.c\n")
521
522
result = self.run_bzr('status test1.c')[0]
522
523
self.assertContainsRe(result, "unknown:\n test1.c\n")
523
524
short_result = self.run_bzr('status --short test1.c')[0]
524
self.assertContainsRe(short_result, "\\? test1.c\n")
525
self.assertContainsRe(short_result, "\? test1.c\n")
526
527
result = self.run_bzr('status test1.c~')[0]
527
528
self.assertContainsRe(result, "ignored:\n test1.c~\n")
534
535
self.assertContainsRe(short_result, "I test1.c~\nI test2.c~\n")
536
537
result = self.run_bzr('status test1.c test1.c~ test2.c~')[0]
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")
538
self.assertContainsRe(result, "unknown:\n test1.c\nignored:\n test1.c~\n test2.c~\n")
539
short_result = self.run_bzr('status --short test1.c test1.c~ test2.c~')[0]
540
self.assertContainsRe(short_result, "\? test1.c\nI test1.c~\nI test2.c~\n")
544
542
def test_status_write_lock(self):
545
543
"""Test that status works without fetching history and
551
549
wt = self.make_branch_and_tree('branch1')
553
551
wt.commit('Empty commit 1')
554
wt2 = b.controldir.sprout('branch2').open_workingtree()
552
wt2 = b.bzrdir.sprout('branch2').open_workingtree()
555
553
wt2.commit('Empty commit 2')
556
554
out, err = self.run_bzr('status branch1 -rbranch:branch2')
557
555
self.assertEqual('', out)
566
564
self.build_tree(['bye.c'])
568
566
self.assertStatus([
571
'1 shelf exists. See "brz shelve --list" for details.\n',
569
'1 shelf exists. See "bzr shelve --list" for details.\n',
574
572
self.run_bzr(['shelve', '--all', '-m', 'bar'])
627
625
self.build_tree(['world.txt'])
628
626
result = self.run_bzr("status -r 0")[0]
629
self.assertContainsRe(result, "added:\n hello.txt\n"
627
self.assertContainsRe(result, "added:\n hello.txt\n" \
630
628
"unknown:\n world.txt\n")
631
629
result2 = self.run_bzr("status -r 0..")[0]
632
630
self.assertEqual(result2, result)
649
647
self.build_tree(['world.txt'])
650
648
result = self.run_bzr("status -S -r 0")[0]
651
self.assertContainsRe(result, "[+]N hello.txt\n"
649
self.assertContainsRe(result, "[+]N hello.txt\n" \
652
650
"[?] world.txt\n")
653
651
result2 = self.run_bzr("status -S -r 0..")[0]
654
652
self.assertEqual(result2, result)
712
710
tree.commit('added file')
714
712
self.build_tree(['file/'])
715
self.assertStatusContains(
716
'kind changed:\n file \\(file => directory\\)')
713
self.assertStatusContains('kind changed:\n file \(file => directory\)')
717
714
tree.rename_one('file', 'directory')
718
self.assertStatusContains('renamed:\n file => directory/\n'
715
self.assertStatusContains('renamed:\n file/ => directory/\n' \
719
716
'modified:\n directory/\n')
720
717
rmdir('directory')
721
718
self.assertStatusContains('removed:\n file\n')
729
726
self.build_tree(['file/'])
730
727
self.assertStatusContains('K file => file/',
732
729
tree.rename_one('file', 'directory')
733
730
self.assertStatusContains('RK file => directory/',
735
732
rmdir('directory')
736
733
self.assertStatusContains('RD file => directory',
739
736
def test_status_illegal_revision_specifiers(self):
740
737
out, err = self.run_bzr('status -r 1..23..123', retcode=3)
757
754
def test_pending_specific_files(self):
758
755
"""With a specific file list, pending merges are not shown."""
759
756
tree = self.make_branch_and_tree('tree')
760
self.build_tree_contents([('tree/a', b'content of a\n')])
757
self.build_tree_contents([('tree/a', 'content of a\n')])
762
759
r1_id = tree.commit('one')
763
alt = tree.controldir.sprout('alt').open_workingtree()
764
self.build_tree_contents([('alt/a', b'content of a\nfrom alt\n')])
760
alt = tree.bzrdir.sprout('alt').open_workingtree()
761
self.build_tree_contents([('alt/a', 'content of a\nfrom alt\n')])
765
762
alt_id = alt.commit('alt')
766
763
tree.merge_from_branch(alt.branch)
767
764
output = self.make_utf8_encoded_stringio()
768
765
show_tree_status(tree, to_file=output)
769
self.assertContainsRe(output.getvalue(), b'pending merge')
766
self.assertContainsRe(output.getvalue(), 'pending merge')
770
767
out, err = self.run_bzr('status tree/a')
771
768
self.assertNotContainsRe(out, 'pending merge')
778
775
working_tree = self.make_branch_and_tree(u'.')
779
776
filename = u'hell\u00d8'
781
self.build_tree_contents([(filename, b'contents of hello')])
778
self.build_tree_contents([(filename, 'contents of hello')])
782
779
except UnicodeEncodeError:
783
780
raise TestSkipped("can't build unicode working tree in "
784
"filesystem encoding %s" % sys.getfilesystemencoding())
781
"filesystem encoding %s" % sys.getfilesystemencoding())
785
782
working_tree.add(filename)
786
783
return working_tree