/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_status.py

  • Committer: Martin von Gagern
  • Date: 2010-04-20 08:47:38 UTC
  • mfrom: (5167 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5195.
  • Revision ID: martin.vgagern@gmx.net-20100420084738-ygymnqmdllzrhpfn
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Tests of status command.
18
18
 
19
19
Most of these depend on the particular formatting used.
20
 
As such they really are blackbox tests even though some of the 
 
20
As such they really are blackbox tests even though some of the
21
21
tests are not using self.capture. If we add tests for the programmatic
22
22
interface later, they will be non blackbox tests.
23
23
"""
32
32
    bzrdir,
33
33
    conflicts,
34
34
    errors,
 
35
    osutils,
35
36
    )
36
37
import bzrlib.branch
37
38
from bzrlib.osutils import pathjoin
42
43
 
43
44
 
44
45
class BranchStatus(TestCaseWithTransport):
45
 
    
 
46
 
46
47
    def assertStatus(self, expected_lines, working_tree,
47
 
        revision=None, short=False, pending=True):
 
48
        revision=None, short=False, pending=True, verbose=False):
48
49
        """Run status in working_tree and look for output.
49
 
        
 
50
 
50
51
        :param expected_lines: The lines to look for.
51
52
        :param working_tree: The tree to run status in.
52
53
        """
53
54
        output_string = self.status_string(working_tree, revision, short,
54
 
                pending)
 
55
                pending, verbose)
55
56
        self.assertEqual(expected_lines, output_string.splitlines(True))
56
 
    
57
 
    def status_string(self, wt, revision=None, short=False, pending=True):
 
57
 
 
58
    def status_string(self, wt, revision=None, short=False, pending=True,
 
59
        verbose=False):
58
60
        # use a real file rather than StringIO because it doesn't handle
59
61
        # Unicode very well.
60
62
        tof = codecs.getwriter('utf-8')(TemporaryFile())
61
63
        show_tree_status(wt, to_file=tof, revision=revision, short=short,
62
 
                show_pending=pending)
 
64
                show_pending=pending, verbose=verbose)
63
65
        tof.seek(0)
64
66
        return tof.read().decode('utf-8')
65
67
 
94
96
                'unknown:\n',
95
97
                '  bye.c\n',
96
98
                '  hello.c\n',
 
99
                'pending merge tips: (use -v to see all merge revisions)\n',
 
100
                '  (ghost) pending@pending-0-0\n',
 
101
            ],
 
102
            wt)
 
103
        self.assertStatus([
 
104
                'unknown:\n',
 
105
                '  bye.c\n',
 
106
                '  hello.c\n',
97
107
                'pending merges:\n',
98
108
                '  (ghost) pending@pending-0-0\n',
99
109
            ],
100
 
            wt)
 
110
            wt, verbose=True)
101
111
        self.assertStatus([
102
112
                '?   bye.c\n',
103
113
                '?   hello.c\n',
137
147
        self.build_tree(['more.c'])
138
148
        wt.add('more.c')
139
149
        wt.commit('Another test message')
140
 
        
 
150
 
141
151
        revs.append(RevisionSpec.from_string('1'))
142
152
        self.assertStatus([
143
153
                'added:\n',
158
168
        wt2 = b_2_dir.open_workingtree()
159
169
        wt.commit(u"\N{TIBETAN DIGIT TWO} Empty commit 2")
160
170
        wt2.merge_from_branch(wt.branch)
161
 
        message = self.status_string(wt2)
 
171
        message = self.status_string(wt2, verbose=True)
162
172
        self.assertStartsWith(message, "pending merges:\n")
163
173
        self.assertEndsWith(message, "Empty commit 2\n")
164
174
        wt2.commit("merged")
166
176
        wt.commit("Empty commit 3 " +
167
177
                   "blah blah blah blah " * 100)
168
178
        wt2.merge_from_branch(wt.branch)
169
 
        message = self.status_string(wt2)
 
179
        message = self.status_string(wt2, verbose=True)
170
180
        self.assertStartsWith(message, "pending merges:\n")
171
181
        self.assert_("Empty commit 3" in message)
172
182
        self.assertEndsWith(message, "...\n")
196
206
        wt.add('directory')
197
207
        wt.add('test.c')
198
208
        wt.commit('testing')
199
 
        
 
209
 
200
210
        self.assertStatus([
201
211
                'unknown:\n',
202
212
                '  bye.c\n',
215
225
        tof = StringIO()
216
226
        self.assertRaises(errors.PathsDoNotExist,
217
227
                          show_tree_status,
218
 
                          wt, specific_files=['bye.c','test.c','absent.c'], 
 
228
                          wt, specific_files=['bye.c','test.c','absent.c'],
219
229
                          to_file=tof)
220
 
        
 
230
 
221
231
        tof = StringIO()
222
232
        show_tree_status(wt, specific_files=['directory'], to_file=tof)
223
233
        tof.seek(0)
274
284
        self.assertEqualDiff('conflicts:\n  Contents conflict in dir2/file1\n',
275
285
                             tof.getvalue())
276
286
 
 
287
    def _prepare_nonexistent(self):
 
288
        wt = self.make_branch_and_tree('.')
 
289
        self.assertStatus([], wt)
 
290
        self.build_tree(['FILE_A', 'FILE_B', 'FILE_C', 'FILE_D', 'FILE_E', ])
 
291
        wt.add('FILE_A')
 
292
        wt.add('FILE_B')
 
293
        wt.add('FILE_C')
 
294
        wt.add('FILE_D')
 
295
        wt.add('FILE_E')
 
296
        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.')
 
299
        unlink('FILE_E')  # FILE_E will be versioned but missing
 
300
        open('FILE_Q', 'w').write('FILE_Q is added but not committed.')
 
301
        wt.add('FILE_Q')  # FILE_Q will be added but not committed
 
302
        open('UNVERSIONED_BUT_EXISTING', 'w')
 
303
        return wt
 
304
 
277
305
    def test_status_nonexistent_file(self):
278
306
        # files that don't exist in either the basis tree or working tree
279
307
        # should give an error
280
 
        wt = self.make_branch_and_tree('.')
281
 
        out, err = self.run_bzr('status does-not-exist', retcode=3)
282
 
        self.assertContainsRe(err, r'do not exist.*does-not-exist')
 
308
        wt = self._prepare_nonexistent()
 
309
        self.assertStatus([
 
310
            'removed:\n',
 
311
            '  FILE_E\n',
 
312
            'added:\n',
 
313
            '  FILE_Q\n',
 
314
            'modified:\n',
 
315
            '  FILE_B\n',
 
316
            '  FILE_C\n',
 
317
            'unknown:\n',
 
318
            '  UNVERSIONED_BUT_EXISTING\n',
 
319
            ],
 
320
            wt)
 
321
        self.assertStatus([
 
322
            ' M  FILE_B\n',
 
323
            ' M  FILE_C\n',
 
324
            ' D  FILE_E\n',
 
325
            '+N  FILE_Q\n',
 
326
            '?   UNVERSIONED_BUT_EXISTING\n',
 
327
            ],
 
328
            wt, short=True)
 
329
 
 
330
        # Okay, everything's looking good with the existent files.
 
331
        # Let's see what happens when we throw in non-existent files.
 
332
 
 
333
        # bzr st [--short] NONEXISTENT '
 
334
        expected = [
 
335
          'nonexistent:\n',
 
336
          '  NONEXISTENT\n',
 
337
          ]
 
338
        out, err = self.run_bzr('status NONEXISTENT', retcode=3)
 
339
        self.assertEqual(expected, out.splitlines(True))
 
340
        self.assertContainsRe(err,
 
341
                              r'.*ERROR: Path\(s\) do not exist: '
 
342
                              'NONEXISTENT.*')
 
343
        expected = [
 
344
          'X:   NONEXISTENT\n',
 
345
          ]
 
346
        out, err = self.run_bzr('status --short NONEXISTENT', retcode=3)
 
347
        self.assertContainsRe(err,
 
348
                              r'.*ERROR: Path\(s\) do not exist: '
 
349
                              'NONEXISTENT.*')
 
350
 
 
351
    def test_status_nonexistent_file_with_others(self):
 
352
        # bzr st [--short] NONEXISTENT ...others..
 
353
        wt = self._prepare_nonexistent()
 
354
        expected = [
 
355
          'removed:\n',
 
356
          '  FILE_E\n',
 
357
          'modified:\n',
 
358
          '  FILE_B\n',
 
359
          '  FILE_C\n',
 
360
          'nonexistent:\n',
 
361
          '  NONEXISTENT\n',
 
362
          ]
 
363
        out, err = self.run_bzr('status NONEXISTENT '
 
364
                                'FILE_A FILE_B FILE_C FILE_D FILE_E',
 
365
                                retcode=3)
 
366
        self.assertEqual(expected, out.splitlines(True))
 
367
        self.assertContainsRe(err,
 
368
                              r'.*ERROR: Path\(s\) do not exist: '
 
369
                              'NONEXISTENT.*')
 
370
        expected = [
 
371
          ' D  FILE_E\n',
 
372
          ' M  FILE_C\n',
 
373
          ' M  FILE_B\n',
 
374
          'X   NONEXISTENT\n',
 
375
          ]
 
376
        out, err = self.run_bzr('status --short NONEXISTENT '
 
377
                                'FILE_A FILE_B FILE_C FILE_D FILE_E',
 
378
                                retcode=3)
 
379
        self.assertEqual(expected, out.splitlines(True))
 
380
        self.assertContainsRe(err,
 
381
                              r'.*ERROR: Path\(s\) do not exist: '
 
382
                              'NONEXISTENT.*')
 
383
 
 
384
    def test_status_multiple_nonexistent_files(self):
 
385
        # bzr st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
 
386
        wt = self._prepare_nonexistent()
 
387
        expected = [
 
388
          'removed:\n',
 
389
          '  FILE_E\n',
 
390
          'modified:\n',
 
391
          '  FILE_B\n',
 
392
          '  FILE_C\n',
 
393
          'nonexistent:\n',
 
394
          '  ANOTHER_NONEXISTENT\n',
 
395
          '  NONEXISTENT\n',
 
396
          ]
 
397
        out, err = self.run_bzr('status NONEXISTENT '
 
398
                                'FILE_A FILE_B ANOTHER_NONEXISTENT '
 
399
                                'FILE_C FILE_D FILE_E', retcode=3)
 
400
        self.assertEqual(expected, out.splitlines(True))
 
401
        self.assertContainsRe(err,
 
402
                              r'.*ERROR: Path\(s\) do not exist: '
 
403
                              'ANOTHER_NONEXISTENT NONEXISTENT.*')
 
404
        expected = [
 
405
          ' D  FILE_E\n',
 
406
          ' M  FILE_C\n',
 
407
          ' M  FILE_B\n',
 
408
          'X   ANOTHER_NONEXISTENT\n',
 
409
          'X   NONEXISTENT\n',
 
410
          ]
 
411
        out, err = self.run_bzr('status --short NONEXISTENT '
 
412
                                'FILE_A FILE_B ANOTHER_NONEXISTENT '
 
413
                                'FILE_C FILE_D FILE_E', retcode=3)
 
414
        self.assertEqual(expected, out.splitlines(True))
 
415
        self.assertContainsRe(err,
 
416
                              r'.*ERROR: Path\(s\) do not exist: '
 
417
                              'ANOTHER_NONEXISTENT NONEXISTENT.*')
 
418
 
 
419
    def test_status_nonexistent_file_with_unversioned(self):
 
420
        # bzr st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
 
421
        wt = self._prepare_nonexistent()
 
422
        expected = [
 
423
          'removed:\n',
 
424
          '  FILE_E\n',
 
425
          'added:\n',
 
426
          '  FILE_Q\n',
 
427
          'modified:\n',
 
428
          '  FILE_B\n',
 
429
          '  FILE_C\n',
 
430
          'unknown:\n',
 
431
          '  UNVERSIONED_BUT_EXISTING\n',
 
432
          'nonexistent:\n',
 
433
          '  NONEXISTENT\n',
 
434
          ]
 
435
        out, err = self.run_bzr('status NONEXISTENT '
 
436
                                'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
 
437
                                'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
 
438
        self.assertEqual(expected, out.splitlines(True))
 
439
        self.assertContainsRe(err,
 
440
                              r'.*ERROR: Path\(s\) do not exist: '
 
441
                              'NONEXISTENT.*')
 
442
        expected = [
 
443
          '+N  FILE_Q\n',
 
444
          '?   UNVERSIONED_BUT_EXISTING\n',
 
445
          ' D  FILE_E\n',
 
446
          ' M  FILE_C\n',
 
447
          ' M  FILE_B\n',
 
448
          'X   NONEXISTENT\n',
 
449
          ]
 
450
        out, err = self.run_bzr('status --short NONEXISTENT '
 
451
                                'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
 
452
                                'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
 
453
        self.assertEqual(expected, out.splitlines(True))
 
454
        self.assertContainsRe(err,
 
455
                              r'.*ERROR: Path\(s\) do not exist: '
 
456
                              'NONEXISTENT.*')
283
457
 
284
458
    def test_status_out_of_date(self):
285
459
        """Simulate status of out-of-date tree after remote push"""
298
472
        self.assertEqual("working tree is out of date, run 'bzr update'\n",
299
473
                         err)
300
474
 
 
475
    def test_status_on_ignored(self):
 
476
        """Tests branch status on an unversioned file which is considered ignored.
 
477
 
 
478
        See https://bugs.launchpad.net/bzr/+bug/40103
 
479
        """
 
480
        tree = self.make_branch_and_tree('.')
 
481
 
 
482
        self.build_tree(['test1.c', 'test1.c~', 'test2.c~'])
 
483
        result = self.run_bzr('status')[0]
 
484
        self.assertContainsRe(result, "unknown:\n  test1.c\n")
 
485
        short_result = self.run_bzr('status --short')[0]
 
486
        self.assertContainsRe(short_result, "\?   test1.c\n")
 
487
 
 
488
        result = self.run_bzr('status test1.c')[0]
 
489
        self.assertContainsRe(result, "unknown:\n  test1.c\n")
 
490
        short_result = self.run_bzr('status --short test1.c')[0]
 
491
        self.assertContainsRe(short_result, "\?   test1.c\n")
 
492
 
 
493
        result = self.run_bzr('status test1.c~')[0]
 
494
        self.assertContainsRe(result, "ignored:\n  test1.c~\n")
 
495
        short_result = self.run_bzr('status --short test1.c~')[0]
 
496
        self.assertContainsRe(short_result, "I   test1.c~\n")
 
497
 
 
498
        result = self.run_bzr('status test1.c~ test2.c~')[0]
 
499
        self.assertContainsRe(result, "ignored:\n  test1.c~\n  test2.c~\n")
 
500
        short_result = self.run_bzr('status --short test1.c~ test2.c~')[0]
 
501
        self.assertContainsRe(short_result, "I   test1.c~\nI   test2.c~\n")
 
502
 
 
503
        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")
 
507
 
301
508
    def test_status_write_lock(self):
302
509
        """Test that status works without fetching history and
303
510
        having a write lock.
320
527
        super(CheckoutStatus, self).setUp()
321
528
        mkdir('codir')
322
529
        chdir('codir')
323
 
        
 
530
 
324
531
    def make_branch_and_tree(self, relpath):
325
532
        source = self.make_branch(pathjoin('..', relpath))
326
533
        checkout = bzrdir.BzrDirMetaFormat1().initialize(relpath)
327
 
        bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
 
534
        bzrlib.branch.BranchReferenceFormat().initialize(checkout,
 
535
            target_branch=source)
328
536
        return checkout.create_workingtree()
329
537
 
330
538
 
421
629
        result2 = self.run_bzr("status -SV -r 0..")[0]
422
630
        self.assertEquals(result2, result)
423
631
 
424
 
    def assertStatusContains(self, pattern):
 
632
    def assertStatusContains(self, pattern, short=False):
425
633
        """Run status, and assert it contains the given pattern"""
426
 
        result = self.run_bzr("status --short")[0]
 
634
        if short:
 
635
            result = self.run_bzr("status --short")[0]
 
636
        else:
 
637
            result = self.run_bzr("status")[0]
427
638
        self.assertContainsRe(result, pattern)
428
639
 
 
640
    def test_kind_change_plain(self):
 
641
        tree = self.make_branch_and_tree('.')
 
642
        self.build_tree(['file'])
 
643
        tree.add('file')
 
644
        tree.commit('added file')
 
645
        unlink('file')
 
646
        self.build_tree(['file/'])
 
647
        self.assertStatusContains('kind changed:\n  file \(file => directory\)')
 
648
        tree.rename_one('file', 'directory')
 
649
        self.assertStatusContains('renamed:\n  file/ => directory/\n' \
 
650
                                  'modified:\n  directory/\n')
 
651
        rmdir('directory')
 
652
        self.assertStatusContains('removed:\n  file\n')
 
653
 
429
654
    def test_kind_change_short(self):
430
655
        tree = self.make_branch_and_tree('.')
431
656
        self.build_tree(['file'])
433
658
        tree.commit('added file')
434
659
        unlink('file')
435
660
        self.build_tree(['file/'])
436
 
        self.assertStatusContains('K  file => file/')
 
661
        self.assertStatusContains('K  file => file/',
 
662
                                   short=True)
437
663
        tree.rename_one('file', 'directory')
438
 
        self.assertStatusContains('RK  file => directory/')
 
664
        self.assertStatusContains('RK  file => directory/',
 
665
                                   short=True)
439
666
        rmdir('directory')
440
 
        self.assertStatusContains('RD  file => directory')
 
667
        self.assertStatusContains('RD  file => directory',
 
668
                                   short=True)
441
669
 
442
670
    def test_status_illegal_revision_specifiers(self):
443
671
        out, err = self.run_bzr('status -r 1..23..123', retcode=3)
469
697
        tree.merge_from_branch(alt.branch)
470
698
        output = self.make_utf8_encoded_stringio()
471
699
        show_tree_status(tree, to_file=output)
472
 
        self.assertContainsRe(output.getvalue(), 'pending merges:')
 
700
        self.assertContainsRe(output.getvalue(), 'pending merge')
473
701
        out, err = self.run_bzr('status tree/a')
474
 
        self.assertNotContainsRe(out, 'pending merges:')
 
702
        self.assertNotContainsRe(out, 'pending merge')
475
703
 
476
704
 
477
705
class TestStatusEncodings(TestCaseWithTransport):
478
 
    
 
706
 
479
707
    def setUp(self):
480
708
        TestCaseWithTransport.setUp(self)
481
 
        self.user_encoding = bzrlib.user_encoding
 
709
        self.user_encoding = osutils._cached_user_encoding
482
710
        self.stdout = sys.stdout
483
711
 
484
712
    def tearDown(self):
485
 
        bzrlib.user_encoding = self.user_encoding
 
713
        osutils._cached_user_encoding = self.user_encoding
486
714
        sys.stdout = self.stdout
487
715
        TestCaseWithTransport.tearDown(self)
488
716
 
500
728
 
501
729
    def test_stdout_ascii(self):
502
730
        sys.stdout = StringIO()
503
 
        bzrlib.user_encoding = 'ascii'
 
731
        osutils._cached_user_encoding = 'ascii'
504
732
        working_tree = self.make_uncommitted_tree()
505
733
        stdout, stderr = self.run_bzr("status")
506
734
 
511
739
 
512
740
    def test_stdout_latin1(self):
513
741
        sys.stdout = StringIO()
514
 
        bzrlib.user_encoding = 'latin-1'
 
742
        osutils._cached_user_encoding = 'latin-1'
515
743
        working_tree = self.make_uncommitted_tree()
516
744
        stdout, stderr = self.run_bzr('status')
517
745