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
39
from bzrlib.osutils import pathjoin
40
from bzrlib.revisionspec import RevisionSpec
41
from bzrlib.status import show_tree_status
42
from bzrlib.tests import TestCaseWithTransport, TestSkipped
43
from bzrlib.workingtree import WorkingTree
38
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
46
50
class BranchStatus(TestCaseWithTransport):
50
54
# As TestCase.setUp clears all hooks, we install this default
51
55
# post_status hook handler for the test.
52
56
status.hooks.install_named_hook('post_status',
53
status._show_shelve_summary,
57
status._show_shelve_summary,
56
60
def assertStatus(self, expected_lines, working_tree, specific_files=None,
57
revision=None, short=False, pending=True, verbose=False):
61
revision=None, short=False, pending=True, verbose=False):
58
62
"""Run status in working_tree and look for output.
60
64
:param expected_lines: The lines to look for.
61
65
:param working_tree: The tree to run status in.
63
67
output_string = self.status_string(working_tree, specific_files, revision, short,
65
69
self.assertEqual(expected_lines, output_string.splitlines(True))
67
71
def status_string(self, wt, specific_files=None, revision=None,
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')
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')
78
79
def test_branch_status(self):
79
80
"""Test basic branch status"""
88
89
self.build_tree(['hello.c', 'bye.c'])
89
90
self.assertStatus([
95
96
self.assertStatus([
101
102
# add a commit to allow showing pending merges.
102
103
wt.commit('create a parent to allow testing merge output')
104
wt.add_parent_tree_id('pending@pending-0-0')
105
wt.add_parent_tree_id(b'pending@pending-0-0')
105
106
self.assertStatus([
109
'pending merge tips: (use -v to see all merge revisions)\n',
110
' (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',
113
114
self.assertStatus([
118
' (ghost) pending@pending-0-0\n',
119
' (ghost) pending@pending-0-0\n',
120
121
wt, verbose=True)
121
122
self.assertStatus([
124
'P (ghost) pending@pending-0-0\n',
125
'P (ghost) pending@pending-0-0\n',
127
128
self.assertStatus([
132
133
wt, pending=False)
133
134
self.assertStatus([
137
138
wt, short=True, pending=False)
183
184
self.assertEndsWith(message, "Empty commit 2\n")
184
185
wt2.commit("merged")
185
186
# must be long to make sure we see elipsis at the end
186
wt.commit("Empty commit 3 " +
187
"blah blah blah blah " * 100)
187
wt.commit("Empty commit 3 "
188
+ "blah blah blah blah " * 100)
188
189
wt2.merge_from_branch(wt.branch)
189
190
message = self.status_string(wt2, verbose=True)
190
191
self.assertStartsWith(message, "pending merges:\n")
191
self.assert_("Empty commit 3" in message)
192
self.assertTrue("Empty commit 3" in message)
192
193
self.assertEndsWith(message, "...\n")
194
195
def test_tree_status_ignores(self):
198
199
wt.commit('commit .bzrignore')
199
200
self.build_tree(['foo.c', 'foo.c~'])
200
201
self.assertStatus([
205
206
self.assertStatus([
210
211
def test_tree_status_specific_files(self):
211
212
"""Tests branch status with given specific files"""
212
213
wt = self.make_branch_and_tree('.')
215
self.build_tree(['directory/','directory/hello.c',
216
'bye.c','test.c','dir2/',
216
self.build_tree(['directory/', 'directory/hello.c',
217
'bye.c', 'test.c', 'dir2/',
218
219
wt.add('directory')
222
223
unlink('missing.c')
224
225
self.assertStatus([
230
' directory/hello.c\n'
231
' directory/hello.c\n'
234
235
self.assertStatus([
238
'? directory/hello.c\n'
238
'? directory/hello.c\n',
243
244
self.assertRaises(errors.PathsDoNotExist,
244
245
show_tree_status,
245
wt, specific_files=['bye.c','test.c','absent.c'],
246
wt, specific_files=['bye.c', 'test.c', 'absent.c'],
249
250
show_tree_status(wt, specific_files=['directory'], to_file=tof)
251
self.assertEquals(tof.readlines(),
253
' directory/hello.c\n'
252
self.assertEqual(tof.readlines(),
254
' directory/hello.c\n'
256
257
show_tree_status(wt, specific_files=['directory'], to_file=tof,
259
self.assertEquals(tof.readlines(), ['? directory/hello.c\n'])
260
self.assertEqual(tof.readlines(), ['? directory/hello.c\n'])
262
263
show_tree_status(wt, specific_files=['dir2'], to_file=tof)
264
self.assertEquals(tof.readlines(),
265
self.assertEqual(tof.readlines(),
269
270
show_tree_status(wt, specific_files=['dir2'], to_file=tof, short=True)
271
self.assertEquals(tof.readlines(), ['? dir2/\n'])
272
self.assertEqual(tof.readlines(), ['? dir2/\n'])
274
275
revs = [RevisionSpec.from_string('0'), RevisionSpec.from_string('1')]
275
276
show_tree_status(wt, specific_files=['test.c'], to_file=tof,
276
277
short=True, revision=revs)
278
self.assertEquals(tof.readlines(), ['+N test.c\n'])
279
self.assertEqual(tof.readlines(), ['+N test.c\n'])
281
282
show_tree_status(wt, specific_files=['missing.c'], to_file=tof)
283
self.assertEquals(tof.readlines(),
284
self.assertEqual(tof.readlines(),
288
289
show_tree_status(wt, specific_files=['missing.c'], to_file=tof,
291
self.assertEquals(tof.readlines(),
292
self.assertEqual(tof.readlines(),
294
295
def test_specific_files_conflicts(self):
295
296
tree = self.make_branch_and_tree('.')
296
297
self.build_tree(['dir2/'])
298
299
tree.commit('added dir2')
299
tree.set_conflicts(conflicts.ConflictList(
300
[conflicts.ContentsConflict('foo')]))
300
tree.set_conflicts([conflicts.ContentsConflict('foo')])
302
302
show_tree_status(tree, specific_files=['dir2'], to_file=tof)
303
self.assertEqualDiff('', tof.getvalue())
304
tree.set_conflicts(conflicts.ConflictList(
305
[conflicts.ContentsConflict('dir2')]))
303
self.assertEqualDiff(b'', tof.getvalue())
304
tree.set_conflicts([conflicts.ContentsConflict('dir2')])
307
306
show_tree_status(tree, specific_files=['dir2'], to_file=tof)
308
307
self.assertEqualDiff('conflicts:\n Contents conflict in dir2\n',
311
tree.set_conflicts(conflicts.ConflictList(
312
[conflicts.ContentsConflict('dir2/file1')]))
310
tree.set_conflicts([conflicts.ContentsConflict('dir2/file1')])
314
312
show_tree_status(tree, specific_files=['dir2'], to_file=tof)
315
313
self.assertEqualDiff('conflicts:\n Contents conflict in dir2/file1\n',
327
325
wt.commit('Create five empty files.')
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.')
326
with open('FILE_B', 'w') as f:
327
f.write('Modification to file FILE_B.')
328
with open('FILE_C', 'w') as f:
329
f.write('Modification to file FILE_C.')
330
330
unlink('FILE_E') # FILE_E will be versioned but missing
331
with open('FILE_Q', 'w') as f: f.write('FILE_Q is added but not committed.')
331
with open('FILE_Q', 'w') as f:
332
f.write('FILE_Q is added but not committed.')
332
333
wt.add('FILE_Q') # FILE_Q will be added but not committed
333
334
open('UNVERSIONED_BUT_EXISTING', 'w')
361
362
# Okay, everything's looking good with the existent files.
362
363
# Let's see what happens when we throw in non-existent files.
364
# bzr st [--short] NONEXISTENT '
365
# brz st [--short] NONEXISTENT '
369
370
out, err = self.run_bzr('status NONEXISTENT', retcode=3)
370
371
self.assertEqual(expected, out.splitlines(True))
371
372
self.assertContainsRe(err,
372
373
r'.*ERROR: Path\(s\) do not exist: '
377
378
out, err = self.run_bzr('status --short NONEXISTENT', retcode=3)
378
379
self.assertContainsRe(err,
379
380
r'.*ERROR: Path\(s\) do not exist: '
382
383
def test_status_nonexistent_file_with_others(self):
383
# bzr st [--short] NONEXISTENT ...others..
384
# brz st [--short] NONEXISTENT ...others..
384
385
wt = self._prepare_nonexistent()
394
395
out, err = self.run_bzr('status NONEXISTENT '
395
396
'FILE_A FILE_B FILE_C FILE_D FILE_E',
415
416
def test_status_multiple_nonexistent_files(self):
416
# bzr st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
417
# brz st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
417
418
wt = self._prepare_nonexistent()
425
' ANOTHER_NONEXISTENT\n',
426
' ANOTHER_NONEXISTENT\n',
428
429
out, err = self.run_bzr('status NONEXISTENT '
429
430
'FILE_A FILE_B ANOTHER_NONEXISTENT '
430
431
'FILE_C FILE_D FILE_E', retcode=3)
448
449
'ANOTHER_NONEXISTENT NONEXISTENT.*')
450
451
def test_status_nonexistent_file_with_unversioned(self):
451
# bzr st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
452
# brz st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
452
453
wt = self._prepare_nonexistent()
462
' UNVERSIONED_BUT_EXISTING\n',
463
' UNVERSIONED_BUT_EXISTING\n',
466
467
out, err = self.run_bzr('status NONEXISTENT '
467
468
'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
468
469
'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
492
492
def test_status_out_of_date(self):
493
493
"""Simulate status of out-of-date tree after remote push"""
494
494
tree = self.make_branch_and_tree('.')
495
self.build_tree_contents([('a', 'foo\n')])
495
self.build_tree_contents([('a', b'foo\n')])
496
with tree.lock_write():
499
498
tree.commit('add test file')
500
499
# simulate what happens after a remote push
501
tree.set_last_revision("0")
503
# before run another commands we should unlock tree
500
tree.set_last_revision(b"0")
505
501
out, err = self.run_bzr('status')
506
self.assertEqual("working tree is out of date, run 'bzr update'\n",
502
self.assertEqual("working tree is out of date, run 'brz update'\n",
509
505
def test_status_on_ignored(self):
517
513
result = self.run_bzr('status')[0]
518
514
self.assertContainsRe(result, "unknown:\n test1.c\n")
519
515
short_result = self.run_bzr('status --short')[0]
520
self.assertContainsRe(short_result, "\? test1.c\n")
516
self.assertContainsRe(short_result, "\\? test1.c\n")
522
518
result = self.run_bzr('status test1.c')[0]
523
519
self.assertContainsRe(result, "unknown:\n test1.c\n")
524
520
short_result = self.run_bzr('status --short test1.c')[0]
525
self.assertContainsRe(short_result, "\? test1.c\n")
521
self.assertContainsRe(short_result, "\\? test1.c\n")
527
523
result = self.run_bzr('status test1.c~')[0]
528
524
self.assertContainsRe(result, "ignored:\n test1.c~\n")
535
531
self.assertContainsRe(short_result, "I test1.c~\nI test2.c~\n")
537
533
result = self.run_bzr('status test1.c test1.c~ test2.c~')[0]
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")
534
self.assertContainsRe(
535
result, "unknown:\n test1.c\nignored:\n test1.c~\n test2.c~\n")
536
short_result = self.run_bzr(
537
'status --short test1.c test1.c~ test2.c~')[0]
538
self.assertContainsRe(
539
short_result, "\\? test1.c\nI test1.c~\nI test2.c~\n")
542
541
def test_status_write_lock(self):
543
542
"""Test that status works without fetching history and
625
624
self.build_tree(['world.txt'])
626
625
result = self.run_bzr("status -r 0")[0]
627
self.assertContainsRe(result, "added:\n hello.txt\n" \
626
self.assertContainsRe(result, "added:\n hello.txt\n"
628
627
"unknown:\n world.txt\n")
629
628
result2 = self.run_bzr("status -r 0..")[0]
630
self.assertEquals(result2, result)
629
self.assertEqual(result2, result)
632
631
def test_status_short(self):
633
632
tree = self.make_branch_and_tree('.')
647
646
self.build_tree(['world.txt'])
648
647
result = self.run_bzr("status -S -r 0")[0]
649
self.assertContainsRe(result, "[+]N hello.txt\n" \
648
self.assertContainsRe(result, "[+]N hello.txt\n"
650
649
"[?] world.txt\n")
651
650
result2 = self.run_bzr("status -S -r 0..")[0]
652
self.assertEquals(result2, result)
651
self.assertEqual(result2, result)
654
653
def test_status_versioned(self):
655
654
tree = self.make_branch_and_tree('.')
742
742
self.build_tree(['a/a'])
744
744
a_tree.commit('a')
745
b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
745
b_tree = a_tree.controldir.sprout('b').open_workingtree()
746
746
self.build_tree(['b/b'])
748
748
b_tree.commit('b')
750
750
self.run_bzr('merge ../b', working_dir='a')
751
751
out, err = self.run_bzr('status --no-pending', working_dir='a')
752
self.assertEquals(out, "added:\n b\n")
752
self.assertEqual(out, "added:\n b\n")
754
754
def test_pending_specific_files(self):
755
755
"""With a specific file list, pending merges are not shown."""
756
756
tree = self.make_branch_and_tree('tree')
757
self.build_tree_contents([('tree/a', 'content of a\n')])
757
self.build_tree_contents([('tree/a', b'content of a\n')])
759
759
r1_id = tree.commit('one')
760
alt = tree.bzrdir.sprout('alt').open_workingtree()
761
self.build_tree_contents([('alt/a', 'content of a\nfrom alt\n')])
760
alt = tree.controldir.sprout('alt').open_workingtree()
761
self.build_tree_contents([('alt/a', b'content of a\nfrom alt\n')])
762
762
alt_id = alt.commit('alt')
763
763
tree.merge_from_branch(alt.branch)
764
764
output = self.make_utf8_encoded_stringio()
765
765
show_tree_status(tree, to_file=output)
766
self.assertContainsRe(output.getvalue(), 'pending merge')
766
self.assertContainsRe(output.getvalue(), b'pending merge')
767
767
out, err = self.run_bzr('status tree/a')
768
768
self.assertNotContainsRe(out, 'pending merge')