~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: John Arbash Meinel
  • Date: 2008-07-11 21:41:24 UTC
  • mto: This revision was merged to the branch mainline in revision 3543.
  • Revision ID: john@arbash-meinel.com-20080711214124-qi09irlj7pd5cuzg
Shortcut the case when one revision is in the ancestry of the other.

At the cost of a heads() check, when one parent supersedes, we don't have to extract
the text for the other. Changes merge time from 3m37s => 3m21s. Using a
CachingParentsProvider would drop the time down to 3m11s.

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
    bzrdir,
33
33
    conflicts,
34
34
    errors,
35
 
    osutils,
36
35
    )
37
36
import bzrlib.branch
38
37
from bzrlib.osutils import pathjoin
45
44
class BranchStatus(TestCaseWithTransport):
46
45
    
47
46
    def assertStatus(self, expected_lines, working_tree,
48
 
        revision=None, short=False, pending=True, verbose=False):
 
47
        revision=None, short=False, pending=True):
49
48
        """Run status in working_tree and look for output.
50
49
        
51
50
        :param expected_lines: The lines to look for.
52
51
        :param working_tree: The tree to run status in.
53
52
        """
54
53
        output_string = self.status_string(working_tree, revision, short,
55
 
                pending, verbose)
 
54
                pending)
56
55
        self.assertEqual(expected_lines, output_string.splitlines(True))
57
56
    
58
 
    def status_string(self, wt, revision=None, short=False, pending=True,
59
 
        verbose=False):
 
57
    def status_string(self, wt, revision=None, short=False, pending=True):
60
58
        # use a real file rather than StringIO because it doesn't handle
61
59
        # Unicode very well.
62
60
        tof = codecs.getwriter('utf-8')(TemporaryFile())
63
61
        show_tree_status(wt, to_file=tof, revision=revision, short=short,
64
 
                show_pending=pending, verbose=verbose)
 
62
                show_pending=pending)
65
63
        tof.seek(0)
66
64
        return tof.read().decode('utf-8')
67
65
 
96
94
                'unknown:\n',
97
95
                '  bye.c\n',
98
96
                '  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',
107
97
                'pending merges:\n',
108
98
                '  (ghost) pending@pending-0-0\n',
109
99
            ],
110
 
            wt, verbose=True)
 
100
            wt)
111
101
        self.assertStatus([
112
102
                '?   bye.c\n',
113
103
                '?   hello.c\n',
168
158
        wt2 = b_2_dir.open_workingtree()
169
159
        wt.commit(u"\N{TIBETAN DIGIT TWO} Empty commit 2")
170
160
        wt2.merge_from_branch(wt.branch)
171
 
        message = self.status_string(wt2, verbose=True)
 
161
        message = self.status_string(wt2)
172
162
        self.assertStartsWith(message, "pending merges:\n")
173
163
        self.assertEndsWith(message, "Empty commit 2\n")
174
164
        wt2.commit("merged")
176
166
        wt.commit("Empty commit 3 " +
177
167
                   "blah blah blah blah " * 100)
178
168
        wt2.merge_from_branch(wt.branch)
179
 
        message = self.status_string(wt2, verbose=True)
 
169
        message = self.status_string(wt2)
180
170
        self.assertStartsWith(message, "pending merges:\n")
181
171
        self.assert_("Empty commit 3" in message)
182
172
        self.assertEndsWith(message, "...\n")
284
274
        self.assertEqualDiff('conflicts:\n  Contents conflict in dir2/file1\n',
285
275
                             tof.getvalue())
286
276
 
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
 
 
305
277
    def test_status_nonexistent_file(self):
306
278
        # files that don't exist in either the basis tree or working tree
307
279
        # should give an error
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.*')
 
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')
457
283
 
458
284
    def test_status_out_of_date(self):
459
285
        """Simulate status of out-of-date tree after remote push"""
472
298
        self.assertEqual("working tree is out of date, run 'bzr update'\n",
473
299
                         err)
474
300
 
475
 
    def test_status_write_lock(self):
476
 
        """Test that status works without fetching history and
477
 
        having a write lock.
478
 
 
479
 
        See https://bugs.launchpad.net/bzr/+bug/149270
480
 
        """
481
 
        mkdir('branch1')
482
 
        wt = self.make_branch_and_tree('branch1')
483
 
        b = wt.branch
484
 
        wt.commit('Empty commit 1')
485
 
        wt2 = b.bzrdir.sprout('branch2').open_workingtree()
486
 
        wt2.commit('Empty commit 2')
487
 
        out, err = self.run_bzr('status branch1 -rbranch:branch2')
488
 
        self.assertEqual('', out)
489
 
 
490
301
 
491
302
class CheckoutStatus(BranchStatus):
492
303
 
627
438
        b_tree.add('b')
628
439
        b_tree.commit('b')
629
440
 
630
 
        self.run_bzr('merge ../b', working_dir='a')
631
 
        out, err = self.run_bzr('status --no-pending', working_dir='a')
 
441
        chdir('a')
 
442
        self.run_bzr('merge ../b')
 
443
        out, err = self.run_bzr('status --no-pending')
632
444
        self.assertEquals(out, "added:\n  b\n")
633
445
 
634
 
    def test_pending_specific_files(self):
635
 
        """With a specific file list, pending merges are not shown."""
636
 
        tree = self.make_branch_and_tree('tree')
637
 
        self.build_tree_contents([('tree/a', 'content of a\n')])
638
 
        tree.add('a')
639
 
        r1_id = tree.commit('one')
640
 
        alt = tree.bzrdir.sprout('alt').open_workingtree()
641
 
        self.build_tree_contents([('alt/a', 'content of a\nfrom alt\n')])
642
 
        alt_id = alt.commit('alt')
643
 
        tree.merge_from_branch(alt.branch)
644
 
        output = self.make_utf8_encoded_stringio()
645
 
        show_tree_status(tree, to_file=output)
646
 
        self.assertContainsRe(output.getvalue(), 'pending merge')
647
 
        out, err = self.run_bzr('status tree/a')
648
 
        self.assertNotContainsRe(out, 'pending merge')
649
446
 
650
447
 
651
448
class TestStatusEncodings(TestCaseWithTransport):
652
449
    
653
450
    def setUp(self):
654
451
        TestCaseWithTransport.setUp(self)
655
 
        self.user_encoding = osutils._cached_user_encoding
 
452
        self.user_encoding = bzrlib.user_encoding
656
453
        self.stdout = sys.stdout
657
454
 
658
455
    def tearDown(self):
674
471
 
675
472
    def test_stdout_ascii(self):
676
473
        sys.stdout = StringIO()
677
 
        osutils._cached_user_encoding = 'ascii'
 
474
        bzrlib.user_encoding = 'ascii'
678
475
        working_tree = self.make_uncommitted_tree()
679
476
        stdout, stderr = self.run_bzr("status")
680
477
 
685
482
 
686
483
    def test_stdout_latin1(self):
687
484
        sys.stdout = StringIO()
688
 
        osutils._cached_user_encoding = 'latin-1'
 
485
        bzrlib.user_encoding = 'latin-1'
689
486
        working_tree = self.make_uncommitted_tree()
690
487
        stdout, stderr = self.run_bzr('status')
691
488