45
41
class BranchStatus(TestCaseWithTransport):
 
47
43
    def assertStatus(self, expected_lines, working_tree,
 
48
 
        revision=None, short=False, pending=True, verbose=False):
 
 
44
        revision=None, short=False):
 
49
45
        """Run status in working_tree and look for output.
 
51
47
        :param expected_lines: The lines to look for.
 
52
48
        :param working_tree: The tree to run status in.
 
54
 
        output_string = self.status_string(working_tree, revision, short,
 
 
50
        output_string = self.status_string(working_tree, revision, short)
 
56
51
        self.assertEqual(expected_lines, output_string.splitlines(True))
 
58
 
    def status_string(self, wt, revision=None, short=False, pending=True,
 
 
53
    def status_string(self, wt, revision=None, short=False):
 
60
54
        # use a real file rather than StringIO because it doesn't handle
 
61
55
        # Unicode very well.
 
62
56
        tof = codecs.getwriter('utf-8')(TemporaryFile())
 
63
 
        show_tree_status(wt, to_file=tof, revision=revision, short=short,
 
64
 
                show_pending=pending, verbose=verbose)
 
 
57
        show_tree_status(wt, to_file=tof, revision=revision, short=short)
 
66
59
        return tof.read().decode('utf-8')
 
 
167
141
        b_2 = b_2_dir.open_branch()
 
168
142
        wt2 = b_2_dir.open_workingtree()
 
169
143
        wt.commit(u"\N{TIBETAN DIGIT TWO} Empty commit 2")
 
170
 
        wt2.merge_from_branch(wt.branch)
 
171
 
        message = self.status_string(wt2, verbose=True)
 
 
144
        merge(["./branch", -1], [None, None], this_dir = './copy')
 
 
145
        message = self.status_string(wt2)
 
172
146
        self.assertStartsWith(message, "pending merges:\n")
 
173
147
        self.assertEndsWith(message, "Empty commit 2\n")
 
174
148
        wt2.commit("merged")
 
175
149
        # must be long to make sure we see elipsis at the end
 
176
150
        wt.commit("Empty commit 3 " +
 
177
151
                   "blah blah blah blah " * 100)
 
178
 
        wt2.merge_from_branch(wt.branch)
 
179
 
        message = self.status_string(wt2, verbose=True)
 
 
152
        merge(["./branch", -1], [None, None], this_dir = './copy')
 
 
153
        message = self.status_string(wt2)
 
180
154
        self.assertStartsWith(message, "pending merges:\n")
 
181
155
        self.assert_("Empty commit 3" in message)
 
182
156
        self.assertEndsWith(message, "...\n")
 
 
254
228
        self.assertEquals(tof.readlines(), ['?   dir2/\n'])
 
257
 
        revs = [RevisionSpec.from_string('0'), RevisionSpec.from_string('1')]
 
258
 
        show_tree_status(wt, specific_files=['test.c'], to_file=tof,
 
259
 
                         short=True, revision=revs)
 
261
 
        self.assertEquals(tof.readlines(), ['+N  test.c\n'])
 
263
 
    def test_specific_files_conflicts(self):
 
264
 
        tree = self.make_branch_and_tree('.')
 
265
 
        self.build_tree(['dir2/'])
 
267
 
        tree.commit('added dir2')
 
268
 
        tree.set_conflicts(conflicts.ConflictList(
 
269
 
            [conflicts.ContentsConflict('foo')]))
 
271
 
        show_tree_status(tree, specific_files=['dir2'], to_file=tof)
 
272
 
        self.assertEqualDiff('', tof.getvalue())
 
273
 
        tree.set_conflicts(conflicts.ConflictList(
 
274
 
            [conflicts.ContentsConflict('dir2')]))
 
276
 
        show_tree_status(tree, specific_files=['dir2'], to_file=tof)
 
277
 
        self.assertEqualDiff('conflicts:\n  Contents conflict in dir2\n',
 
280
 
        tree.set_conflicts(conflicts.ConflictList(
 
281
 
            [conflicts.ContentsConflict('dir2/file1')]))
 
283
 
        show_tree_status(tree, specific_files=['dir2'], to_file=tof)
 
284
 
        self.assertEqualDiff('conflicts:\n  Contents conflict in dir2/file1\n',
 
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', ])
 
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')
 
305
230
    def test_status_nonexistent_file(self):
 
306
231
        # files that don't exist in either the basis tree or working tree
 
307
232
        # should give an error
 
308
 
        wt = self._prepare_nonexistent()
 
318
 
            '  UNVERSIONED_BUT_EXISTING\n',
 
326
 
            '?   UNVERSIONED_BUT_EXISTING\n',
 
330
 
        # Okay, everything's looking good with the existent files.
 
331
 
        # Let's see what happens when we throw in non-existent files.
 
333
 
        # bzr st [--short] NONEXISTENT '
 
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: '
 
346
 
        out, err = self.run_bzr('status --short NONEXISTENT', retcode=3)
 
347
 
        self.assertContainsRe(err,
 
348
 
                              r'.*ERROR: Path\(s\) do not exist: '
 
351
 
    def test_status_nonexistent_file_with_others(self):
 
352
 
        # bzr st [--short] NONEXISTENT ...others..
 
353
 
        wt = self._prepare_nonexistent()
 
363
 
        out, err = self.run_bzr('status NONEXISTENT '
 
364
 
                                'FILE_A FILE_B FILE_C FILE_D FILE_E',
 
366
 
        self.assertEqual(expected, out.splitlines(True))
 
367
 
        self.assertContainsRe(err,
 
368
 
                              r'.*ERROR: Path\(s\) do not exist: '
 
376
 
        out, err = self.run_bzr('status --short NONEXISTENT '
 
377
 
                                'FILE_A FILE_B FILE_C FILE_D FILE_E',
 
379
 
        self.assertEqual(expected, out.splitlines(True))
 
380
 
        self.assertContainsRe(err,
 
381
 
                              r'.*ERROR: Path\(s\) do not exist: '
 
384
 
    def test_status_multiple_nonexistent_files(self):
 
385
 
        # bzr st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
 
386
 
        wt = self._prepare_nonexistent()
 
394
 
          '  ANOTHER_NONEXISTENT\n',
 
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.*')
 
408
 
          'X   ANOTHER_NONEXISTENT\n',
 
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.*')
 
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()
 
431
 
          '  UNVERSIONED_BUT_EXISTING\n',
 
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: '
 
444
 
          '?   UNVERSIONED_BUT_EXISTING\n',
 
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: '
 
 
233
        wt = self.make_branch_and_tree('.')
 
 
234
        out, err = self.run_bzr('status does-not-exist', retcode=3)
 
 
235
        self.assertContainsRe(err, r'do not exist.*does-not-exist')
 
458
237
    def test_status_out_of_date(self):
 
459
238
        """Simulate status of out-of-date tree after remote push"""
 
 
472
251
        self.assertEqual("working tree is out of date, run 'bzr update'\n",
 
475
 
    def test_status_on_ignored(self):
 
476
 
        """Tests branch status on an unversioned file which is considered ignored.
 
478
 
        See https://bugs.launchpad.net/bzr/+bug/40103
 
480
 
        tree = self.make_branch_and_tree('.')
 
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")
 
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")
 
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")
 
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")
 
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")
 
508
 
    def test_status_write_lock(self):
 
509
 
        """Test that status works without fetching history and
 
512
 
        See https://bugs.launchpad.net/bzr/+bug/149270
 
515
 
        wt = self.make_branch_and_tree('branch1')
 
517
 
        wt.commit('Empty commit 1')
 
518
 
        wt2 = b.bzrdir.sprout('branch2').open_workingtree()
 
519
 
        wt2.commit('Empty commit 2')
 
520
 
        out, err = self.run_bzr('status branch1 -rbranch:branch2')
 
521
 
        self.assertEqual('', out)
 
524
255
class CheckoutStatus(BranchStatus):
 
 
527
258
        super(CheckoutStatus, self).setUp()
 
531
262
    def make_branch_and_tree(self, relpath):
 
532
263
        source = self.make_branch(pathjoin('..', relpath))
 
533
264
        checkout = bzrdir.BzrDirMetaFormat1().initialize(relpath)
 
534
 
        bzrlib.branch.BranchReferenceFormat().initialize(checkout,
 
535
 
            target_branch=source)
 
 
265
        bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
 
536
266
        return checkout.create_workingtree()
 
539
269
class TestStatus(TestCaseWithTransport):
 
541
271
    def test_status_plain(self):
 
542
 
        tree = self.make_branch_and_tree('.')
 
544
274
        self.build_tree(['hello.txt'])
 
545
275
        result = self.run_bzr("status")[0]
 
546
276
        self.assertContainsRe(result, "unknown:\n  hello.txt\n")
 
548
 
        tree.add("hello.txt")
 
 
278
        self.run_bzr("add hello.txt")
 
549
279
        result = self.run_bzr("status")[0]
 
550
280
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
552
 
        tree.commit(message="added")
 
 
282
        self.run_bzr("commit -m added")
 
553
283
        result = self.run_bzr("status -r 0..1")[0]
 
554
284
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
556
 
        result = self.run_bzr("status -c 1")[0]
 
557
 
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
559
286
        self.build_tree(['world.txt'])
 
560
287
        result = self.run_bzr("status -r 0")[0]
 
561
288
        self.assertContainsRe(result, "added:\n  hello.txt\n" \
 
 
607
334
        result2 = self.run_bzr("status --versioned -r 0..")[0]
 
608
335
        self.assertEquals(result2, result)
 
610
 
    def test_status_SV(self):
 
611
 
        tree = self.make_branch_and_tree('.')
 
613
 
        self.build_tree(['hello.txt'])
 
614
 
        result = self.run_bzr("status -SV")[0]
 
615
 
        self.assertNotContainsRe(result, "hello.txt")
 
617
 
        tree.add("hello.txt")
 
618
 
        result = self.run_bzr("status -SV")[0]
 
619
 
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
621
 
        tree.commit(message="added")
 
622
 
        result = self.run_bzr("status -SV -r 0..1")[0]
 
623
 
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
625
 
        self.build_tree(['world.txt'])
 
626
 
        result = self.run_bzr("status -SV -r 0")[0]
 
627
 
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
629
 
        result2 = self.run_bzr("status -SV -r 0..")[0]
 
630
 
        self.assertEquals(result2, result)
 
632
 
    def assertStatusContains(self, pattern, short=False):
 
 
337
    def assertStatusContains(self, pattern):
 
633
338
        """Run status, and assert it contains the given pattern"""
 
635
 
            result = self.run_bzr("status --short")[0]
 
637
 
            result = self.run_bzr("status")[0]
 
 
339
        result = self.run_bzr("status --short")[0]
 
638
340
        self.assertContainsRe(result, pattern)
 
640
 
    def test_kind_change_plain(self):
 
641
 
        tree = self.make_branch_and_tree('.')
 
642
 
        self.build_tree(['file'])
 
644
 
        tree.commit('added 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')
 
652
 
        self.assertStatusContains('removed:\n  file\n')
 
654
342
    def test_kind_change_short(self):
 
655
343
        tree = self.make_branch_and_tree('.')
 
656
344
        self.build_tree(['file'])
 
 
658
346
        tree.commit('added file')
 
660
348
        self.build_tree(['file/'])
 
661
 
        self.assertStatusContains('K  file => file/',
 
 
349
        self.assertStatusContains('K  file => file/')
 
663
350
        tree.rename_one('file', 'directory')
 
664
 
        self.assertStatusContains('RK  file => directory/',
 
 
351
        self.assertStatusContains('RK  file => directory/')
 
666
352
        rmdir('directory')
 
667
 
        self.assertStatusContains('RD  file => directory',
 
670
 
    def test_status_illegal_revision_specifiers(self):
 
671
 
        out, err = self.run_bzr('status -r 1..23..123', retcode=3)
 
672
 
        self.assertContainsRe(err, 'one or two revision specifiers')
 
674
 
    def test_status_no_pending(self):
 
675
 
        a_tree = self.make_branch_and_tree('a')
 
676
 
        self.build_tree(['a/a'])
 
679
 
        b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
 
680
 
        self.build_tree(['b/b'])
 
684
 
        self.run_bzr('merge ../b', working_dir='a')
 
685
 
        out, err = self.run_bzr('status --no-pending', working_dir='a')
 
686
 
        self.assertEquals(out, "added:\n  b\n")
 
688
 
    def test_pending_specific_files(self):
 
689
 
        """With a specific file list, pending merges are not shown."""
 
690
 
        tree = self.make_branch_and_tree('tree')
 
691
 
        self.build_tree_contents([('tree/a', 'content of a\n')])
 
693
 
        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')])
 
696
 
        alt_id = alt.commit('alt')
 
697
 
        tree.merge_from_branch(alt.branch)
 
698
 
        output = self.make_utf8_encoded_stringio()
 
699
 
        show_tree_status(tree, to_file=output)
 
700
 
        self.assertContainsRe(output.getvalue(), 'pending merge')
 
701
 
        out, err = self.run_bzr('status tree/a')
 
702
 
        self.assertNotContainsRe(out, 'pending merge')
 
 
353
        self.assertStatusContains('RD  file => directory')
 
705
356
class TestStatusEncodings(TestCaseWithTransport):
 
708
359
        TestCaseWithTransport.setUp(self)
 
709
 
        self.user_encoding = osutils._cached_user_encoding
 
 
360
        self.user_encoding = bzrlib.user_encoding
 
710
361
        self.stdout = sys.stdout
 
712
363
    def tearDown(self):
 
713
 
        osutils._cached_user_encoding = self.user_encoding
 
 
364
        bzrlib.user_encoding = self.user_encoding
 
714
365
        sys.stdout = self.stdout
 
715
366
        TestCaseWithTransport.tearDown(self)