/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/selftest/teststatus.py

[merge] robertc's integration, updated tests to check for retcode=3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2016 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2005 by Canonical Ltd
 
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
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
16
17
 
17
18
"""Tests of status command.
18
19
 
19
20
Most of these depend on the particular formatting used.
20
 
As such they really are blackbox tests even though some of the
21
 
tests are not using self.capture. If we add tests for the programmatic
22
 
interface later, they will be non blackbox tests.
23
21
"""
24
22
 
25
 
import codecs
26
 
from os import mkdir, chdir, rmdir, unlink
27
 
import sys
28
 
 
29
 
from ... import (
30
 
    conflicts,
31
 
    errors,
32
 
    osutils,
33
 
    status,
34
 
    )
35
 
from breezy.bzr import (
36
 
    bzrdir,
37
 
    )
38
 
import breezy.branch
39
 
from ...osutils import pathjoin
40
 
from ...revisionspec import RevisionSpec
41
 
from ...sixish import (
42
 
    BytesIO,
43
 
    StringIO,
44
 
    PY3,
45
 
    )
46
 
from ...status import show_tree_status
47
 
from .. import TestCaseWithTransport, TestSkipped
48
 
from ...workingtree import WorkingTree
49
 
 
50
 
 
51
 
class BranchStatus(TestCaseWithTransport):
52
 
 
53
 
    def setUp(self):
54
 
        super(BranchStatus, self).setUp()
55
 
        # As TestCase.setUp clears all hooks, we install this default
56
 
        # post_status hook handler for the test.
57
 
        status.hooks.install_named_hook('post_status',
58
 
                                        status._show_shelve_summary,
59
 
                                        'brz status')
60
 
 
61
 
    def assertStatus(self, expected_lines, working_tree, specific_files=None,
62
 
                     revision=None, short=False, pending=True, verbose=False):
63
 
        """Run status in working_tree and look for output.
64
 
 
65
 
        :param expected_lines: The lines to look for.
66
 
        :param working_tree: The tree to run status in.
67
 
        """
68
 
        output_string = self.status_string(working_tree, specific_files, revision, short,
69
 
                                           pending, verbose)
70
 
        self.assertEqual(expected_lines, output_string.splitlines(True))
71
 
 
72
 
    def status_string(self, wt, specific_files=None, revision=None,
73
 
                      short=False, pending=True, verbose=False):
74
 
        uio = self.make_utf8_encoded_stringio()
75
 
        show_tree_status(wt, specific_files=specific_files, to_file=uio,
76
 
                         revision=revision, short=short, show_pending=pending,
77
 
                         verbose=verbose)
78
 
        return uio.getvalue().decode('utf-8')
79
 
 
80
 
    def test_branch_status(self):
 
23
 
 
24
from bzrlib.selftest import TestCaseInTempDir
 
25
from bzrlib.revisionspec import RevisionSpec
 
26
from bzrlib.merge import merge
 
27
from cStringIO import StringIO
 
28
from bzrlib.status import show_status
 
29
from bzrlib.branch import Branch
 
30
from os import mkdir
 
31
from bzrlib.clone import copy_branch
 
32
 
 
33
class BranchStatus(TestCaseInTempDir):
 
34
    
 
35
    def test_branch_status(self): 
81
36
        """Test basic branch status"""
82
 
        wt = self.make_branch_and_tree('.')
83
 
 
84
 
        # status with no commits or files - it must
85
 
        # work and show no output. We do this with no
86
 
        # commits to be sure that it's not going to fail
87
 
        # as a corner case.
88
 
        self.assertStatus([], wt)
89
 
 
 
37
        from cStringIO import StringIO
 
38
        from bzrlib.status import show_status
 
39
        from bzrlib.branch import Branch
 
40
        
 
41
        b = Branch.initialize('.')
 
42
 
 
43
        # status with nothing
 
44
        tof = StringIO()
 
45
        show_status(b, to_file=tof)
 
46
        self.assertEquals(tof.getvalue(), "")
 
47
 
 
48
        tof = StringIO()
90
49
        self.build_tree(['hello.c', 'bye.c'])
91
 
        self.assertStatus([
92
 
            'unknown:\n',
93
 
            '  bye.c\n',
94
 
            '  hello.c\n',
95
 
            ],
96
 
            wt)
97
 
        self.assertStatus([
98
 
            '?   bye.c\n',
99
 
            '?   hello.c\n',
100
 
            ],
101
 
            wt, short=True)
102
 
 
103
 
        # add a commit to allow showing pending merges.
104
 
        wt.commit('create a parent to allow testing merge output')
105
 
 
106
 
        wt.add_parent_tree_id(b'pending@pending-0-0')
107
 
        self.assertStatus([
108
 
            'unknown:\n',
109
 
            '  bye.c\n',
110
 
            '  hello.c\n',
111
 
            'pending merge tips: (use -v to see all merge revisions)\n',
112
 
            '  (ghost) pending@pending-0-0\n',
113
 
            ],
114
 
            wt)
115
 
        self.assertStatus([
116
 
            'unknown:\n',
117
 
            '  bye.c\n',
118
 
            '  hello.c\n',
119
 
            'pending merges:\n',
120
 
            '  (ghost) pending@pending-0-0\n',
121
 
            ],
122
 
            wt, verbose=True)
123
 
        self.assertStatus([
124
 
            '?   bye.c\n',
125
 
            '?   hello.c\n',
126
 
            'P   (ghost) pending@pending-0-0\n',
127
 
            ],
128
 
            wt, short=True)
129
 
        self.assertStatus([
130
 
            'unknown:\n',
131
 
            '  bye.c\n',
132
 
            '  hello.c\n',
133
 
            ],
134
 
            wt, pending=False)
135
 
        self.assertStatus([
136
 
            '?   bye.c\n',
137
 
            '?   hello.c\n',
138
 
            ],
139
 
            wt, short=True, pending=False)
 
50
        b.working_tree().add_pending_merge('pending@pending-0-0')
 
51
        show_status(b, to_file=tof)
 
52
        tof.seek(0)
 
53
        self.assertEquals(tof.readlines(),
 
54
                          ['unknown:\n',
 
55
                           '  bye.c\n',
 
56
                           '  hello.c\n',
 
57
                           'pending merges:\n',
 
58
                           '  pending@pending-0-0\n'
 
59
                           ])
140
60
 
141
61
    def test_branch_status_revisions(self):
142
62
        """Tests branch status with revisions"""
143
 
        wt = self.make_branch_and_tree('.')
 
63
        
 
64
        b = Branch.initialize('.')
144
65
 
 
66
        tof = StringIO()
145
67
        self.build_tree(['hello.c', 'bye.c'])
146
 
        wt.add('hello.c')
147
 
        wt.add('bye.c')
148
 
        wt.commit('Test message')
 
68
        b.add('hello.c')
 
69
        b.add('bye.c')
 
70
        b.working_tree().commit('Test message')
149
71
 
150
 
        revs = [RevisionSpec.from_string('0')]
151
 
        self.assertStatus([
152
 
            'added:\n',
153
 
            '  bye.c\n',
154
 
            '  hello.c\n'
155
 
            ],
156
 
            wt,
157
 
            revision=revs)
 
72
        tof = StringIO()
 
73
        revs =[]
 
74
        revs.append(RevisionSpec(0))
 
75
        
 
76
        show_status(b, to_file=tof, revision=revs)
 
77
        
 
78
        tof.seek(0)
 
79
        self.assertEquals(tof.readlines(),
 
80
                          ['added:\n',
 
81
                           '  bye.c\n',
 
82
                           '  hello.c\n'])
158
83
 
159
84
        self.build_tree(['more.c'])
160
 
        wt.add('more.c')
161
 
        wt.commit('Another test message')
 
85
        b.add('more.c')
 
86
        b.working_tree().commit('Another test message')
 
87
        
 
88
        tof = StringIO()
 
89
        revs.append(RevisionSpec(1))
 
90
        
 
91
        show_status(b, to_file=tof, revision=revs)
 
92
        
 
93
        tof.seek(0)
 
94
        self.assertEquals(tof.readlines(),
 
95
                          ['added:\n',
 
96
                           '  bye.c\n',
 
97
                           '  hello.c\n'])
162
98
 
163
 
        revs.append(RevisionSpec.from_string('1'))
164
 
        self.assertStatus([
165
 
            'added:\n',
166
 
            '  bye.c\n',
167
 
            '  hello.c\n',
168
 
            ],
169
 
            wt,
170
 
            revision=revs)
 
99
    def status_string(self, branch):
 
100
        tof = StringIO()
 
101
        show_status(branch, to_file=tof)
 
102
        tof.seek(0)
 
103
        return tof.getvalue()
171
104
 
172
105
    def test_pending(self):
173
 
        """Pending merges display works, including Unicode"""
 
106
        """Pending merges display works"""
174
107
        mkdir("./branch")
175
 
        wt = self.make_branch_and_tree('branch')
176
 
        b = wt.branch
177
 
        wt.commit("Empty commit 1")
178
 
        b_2_dir = b.controldir.sprout('./copy')
179
 
        b_2 = b_2_dir.open_branch()
180
 
        wt2 = b_2_dir.open_workingtree()
181
 
        wt.commit(u"\N{TIBETAN DIGIT TWO} Empty commit 2")
182
 
        wt2.merge_from_branch(wt.branch)
183
 
        message = self.status_string(wt2, verbose=True)
184
 
        self.assertStartsWith(message, "pending merges:\n")
185
 
        self.assertEndsWith(message, "Empty commit 2\n")
186
 
        wt2.commit("merged")
 
108
        b = Branch.initialize('./branch')
 
109
        b.working_tree().commit("Empty commit 1")
 
110
        b_2 = copy_branch(b, './copy')
 
111
        b.working_tree().commit("Empty commit 2")
 
112
        merge(["./branch", -1], [None, None], this_dir = './copy')
 
113
        message = self.status_string(b_2)
 
114
        self.assert_(message.startswith("pending merges:\n"))
 
115
        self.assert_(message.endswith("Empty commit 2\n")) 
 
116
        b_2.working_tree().commit("merged")
187
117
        # must be long to make sure we see elipsis at the end
188
 
        wt.commit("Empty commit 3 "
189
 
                  + "blah blah blah blah " * 100)
190
 
        wt2.merge_from_branch(wt.branch)
191
 
        message = self.status_string(wt2, verbose=True)
192
 
        self.assertStartsWith(message, "pending merges:\n")
193
 
        self.assertTrue("Empty commit 3" in message)
194
 
        self.assertEndsWith(message, "...\n")
195
 
 
196
 
    def test_tree_status_ignores(self):
197
 
        """Tests branch status with ignores"""
198
 
        wt = self.make_branch_and_tree('.')
199
 
        self.run_bzr('ignore *~')
200
 
        wt.commit('commit .bzrignore')
201
 
        self.build_tree(['foo.c', 'foo.c~'])
202
 
        self.assertStatus([
203
 
            'unknown:\n',
204
 
            '  foo.c\n',
205
 
            ],
206
 
            wt)
207
 
        self.assertStatus([
208
 
            '?   foo.c\n',
209
 
            ],
210
 
            wt, short=True)
211
 
 
212
 
    def test_tree_status_specific_files(self):
 
118
        b.working_tree().commit("Empty commit 3 blah blah blah blah blah blah blah blah blah"
 
119
                 " blah blah blah blah blah blah bleh")
 
120
        merge(["./branch", -1], [None, None], this_dir = './copy')
 
121
        message = self.status_string(b_2)
 
122
        self.assert_(message.startswith("pending merges:\n"))
 
123
        self.assert_("Empty commit 3" in message)
 
124
        self.assert_(message.endswith("...\n")) 
 
125
 
 
126
    def test_branch_status_specific_files(self): 
213
127
        """Tests branch status with given specific files"""
214
 
        wt = self.make_branch_and_tree('.')
215
 
        b = wt.branch
216
 
 
217
 
        self.build_tree(['directory/', 'directory/hello.c',
218
 
                         'bye.c', 'test.c', 'dir2/',
219
 
                         'missing.c'])
220
 
        wt.add('directory')
221
 
        wt.add('test.c')
222
 
        wt.commit('testing')
223
 
        wt.add('missing.c')
224
 
        unlink('missing.c')
225
 
 
226
 
        self.assertStatus([
227
 
            'missing:\n',
228
 
            '  missing.c\n',
229
 
            'unknown:\n',
230
 
            '  bye.c\n',
231
 
            '  dir2/\n',
232
 
            '  directory/hello.c\n'
233
 
            ],
234
 
            wt)
235
 
 
236
 
        self.assertStatus([
237
 
            '?   bye.c\n',
238
 
            '?   dir2/\n',
239
 
            '?   directory/hello.c\n',
240
 
            '+!  missing.c\n',
241
 
            ],
242
 
            wt, short=True)
243
 
 
244
 
        tof = StringIO()
245
 
        self.assertRaises(errors.PathsDoNotExist,
246
 
                          show_tree_status,
247
 
                          wt, specific_files=['bye.c', 'test.c', 'absent.c'],
248
 
                          to_file=tof)
249
 
 
250
 
        tof = StringIO()
251
 
        show_tree_status(wt, specific_files=['directory'], to_file=tof)
252
 
        tof.seek(0)
253
 
        self.assertEqual(tof.readlines(),
254
 
                         ['unknown:\n',
255
 
                          '  directory/hello.c\n'
256
 
                          ])
257
 
        tof = StringIO()
258
 
        show_tree_status(wt, specific_files=['directory'], to_file=tof,
259
 
                         short=True)
260
 
        tof.seek(0)
261
 
        self.assertEqual(tof.readlines(), ['?   directory/hello.c\n'])
262
 
 
263
 
        tof = StringIO()
264
 
        show_tree_status(wt, specific_files=['dir2'], to_file=tof)
265
 
        tof.seek(0)
266
 
        self.assertEqual(tof.readlines(),
267
 
                         ['unknown:\n',
268
 
                          '  dir2/\n'
269
 
                          ])
270
 
        tof = StringIO()
271
 
        show_tree_status(wt, specific_files=['dir2'], to_file=tof, short=True)
272
 
        tof.seek(0)
273
 
        self.assertEqual(tof.readlines(), ['?   dir2/\n'])
274
 
 
275
 
        tof = StringIO()
276
 
        revs = [RevisionSpec.from_string('0'), RevisionSpec.from_string('1')]
277
 
        show_tree_status(wt, specific_files=['test.c'], to_file=tof,
278
 
                         short=True, revision=revs)
279
 
        tof.seek(0)
280
 
        self.assertEqual(tof.readlines(), ['+N  test.c\n'])
281
 
 
282
 
        tof = StringIO()
283
 
        show_tree_status(wt, specific_files=['missing.c'], to_file=tof)
284
 
        tof.seek(0)
285
 
        self.assertEqual(tof.readlines(),
286
 
                         ['missing:\n',
287
 
                          '  missing.c\n'])
288
 
 
289
 
        tof = StringIO()
290
 
        show_tree_status(wt, specific_files=['missing.c'], to_file=tof,
291
 
                         short=True)
292
 
        tof.seek(0)
293
 
        self.assertEqual(tof.readlines(),
294
 
                         ['+!  missing.c\n'])
295
 
 
296
 
    def test_specific_files_conflicts(self):
297
 
        tree = self.make_branch_and_tree('.')
298
 
        self.build_tree(['dir2/'])
299
 
        tree.add('dir2')
300
 
        tree.commit('added dir2')
301
 
        tree.set_conflicts(conflicts.ConflictList(
302
 
            [conflicts.ContentsConflict('foo')]))
303
 
        tof = BytesIO()
304
 
        show_tree_status(tree, specific_files=['dir2'], to_file=tof)
305
 
        self.assertEqualDiff(b'', tof.getvalue())
306
 
        tree.set_conflicts(conflicts.ConflictList(
307
 
            [conflicts.ContentsConflict('dir2')]))
308
 
        tof = StringIO()
309
 
        show_tree_status(tree, specific_files=['dir2'], to_file=tof)
310
 
        self.assertEqualDiff('conflicts:\n  Contents conflict in dir2\n',
311
 
                             tof.getvalue())
312
 
 
313
 
        tree.set_conflicts(conflicts.ConflictList(
314
 
            [conflicts.ContentsConflict('dir2/file1')]))
315
 
        tof = StringIO()
316
 
        show_tree_status(tree, specific_files=['dir2'], to_file=tof)
317
 
        self.assertEqualDiff('conflicts:\n  Contents conflict in dir2/file1\n',
318
 
                             tof.getvalue())
319
 
 
320
 
    def _prepare_nonexistent(self):
321
 
        wt = self.make_branch_and_tree('.')
322
 
        self.assertStatus([], wt)
323
 
        self.build_tree(['FILE_A', 'FILE_B', 'FILE_C', 'FILE_D', 'FILE_E', ])
324
 
        wt.add('FILE_A')
325
 
        wt.add('FILE_B')
326
 
        wt.add('FILE_C')
327
 
        wt.add('FILE_D')
328
 
        wt.add('FILE_E')
329
 
        wt.commit('Create five empty files.')
330
 
        with open('FILE_B', 'w') as f:
331
 
            f.write('Modification to file FILE_B.')
332
 
        with open('FILE_C', 'w') as f:
333
 
            f.write('Modification to file FILE_C.')
334
 
        unlink('FILE_E')  # FILE_E will be versioned but missing
335
 
        with open('FILE_Q', 'w') as f:
336
 
            f.write('FILE_Q is added but not committed.')
337
 
        wt.add('FILE_Q')  # FILE_Q will be added but not committed
338
 
        open('UNVERSIONED_BUT_EXISTING', 'w')
339
 
        return wt
340
 
 
341
 
    def test_status_nonexistent_file(self):
342
 
        # files that don't exist in either the basis tree or working tree
343
 
        # should give an error
344
 
        wt = self._prepare_nonexistent()
345
 
        self.assertStatus([
346
 
            'removed:\n',
347
 
            '  FILE_E\n',
348
 
            'added:\n',
349
 
            '  FILE_Q\n',
350
 
            'modified:\n',
351
 
            '  FILE_B\n',
352
 
            '  FILE_C\n',
353
 
            'unknown:\n',
354
 
            '  UNVERSIONED_BUT_EXISTING\n',
355
 
            ],
356
 
            wt)
357
 
        self.assertStatus([
358
 
            ' M  FILE_B\n',
359
 
            ' M  FILE_C\n',
360
 
            ' D  FILE_E\n',
361
 
            '+N  FILE_Q\n',
362
 
            '?   UNVERSIONED_BUT_EXISTING\n',
363
 
            ],
364
 
            wt, short=True)
365
 
 
366
 
        # Okay, everything's looking good with the existent files.
367
 
        # Let's see what happens when we throw in non-existent files.
368
 
 
369
 
        # brz st [--short] NONEXISTENT '
370
 
        expected = [
371
 
            'nonexistent:\n',
372
 
            '  NONEXISTENT\n',
373
 
            ]
374
 
        out, err = self.run_bzr('status NONEXISTENT', retcode=3)
375
 
        self.assertEqual(expected, out.splitlines(True))
376
 
        self.assertContainsRe(err,
377
 
                              r'.*ERROR: Path\(s\) do not exist: '
378
 
                              'NONEXISTENT.*')
379
 
        expected = [
380
 
            'X:   NONEXISTENT\n',
381
 
            ]
382
 
        out, err = self.run_bzr('status --short NONEXISTENT', retcode=3)
383
 
        self.assertContainsRe(err,
384
 
                              r'.*ERROR: Path\(s\) do not exist: '
385
 
                              'NONEXISTENT.*')
386
 
 
387
 
    def test_status_nonexistent_file_with_others(self):
388
 
        # brz st [--short] NONEXISTENT ...others..
389
 
        wt = self._prepare_nonexistent()
390
 
        expected = [
391
 
            'removed:\n',
392
 
            '  FILE_E\n',
393
 
            'modified:\n',
394
 
            '  FILE_B\n',
395
 
            '  FILE_C\n',
396
 
            'nonexistent:\n',
397
 
            '  NONEXISTENT\n',
398
 
            ]
399
 
        out, err = self.run_bzr('status NONEXISTENT '
400
 
                                'FILE_A FILE_B FILE_C FILE_D FILE_E',
401
 
                                retcode=3)
402
 
        self.assertEqual(expected, out.splitlines(True))
403
 
        self.assertContainsRe(err,
404
 
                              r'.*ERROR: Path\(s\) do not exist: '
405
 
                              'NONEXISTENT.*')
406
 
        expected = [
407
 
            ' M  FILE_B\n',
408
 
            ' M  FILE_C\n',
409
 
            ' D  FILE_E\n',
410
 
            'X   NONEXISTENT\n',
411
 
            ]
412
 
        out, err = self.run_bzr('status --short NONEXISTENT '
413
 
                                'FILE_A FILE_B FILE_C FILE_D FILE_E',
414
 
                                retcode=3)
415
 
        self.assertEqual(expected, out.splitlines(True))
416
 
        self.assertContainsRe(err,
417
 
                              r'.*ERROR: Path\(s\) do not exist: '
418
 
                              'NONEXISTENT.*')
419
 
 
420
 
    def test_status_multiple_nonexistent_files(self):
421
 
        # brz st [--short] NONEXISTENT ... ANOTHER_NONEXISTENT ...
422
 
        wt = self._prepare_nonexistent()
423
 
        expected = [
424
 
            'removed:\n',
425
 
            '  FILE_E\n',
426
 
            'modified:\n',
427
 
            '  FILE_B\n',
428
 
            '  FILE_C\n',
429
 
            'nonexistent:\n',
430
 
            '  ANOTHER_NONEXISTENT\n',
431
 
            '  NONEXISTENT\n',
432
 
            ]
433
 
        out, err = self.run_bzr('status NONEXISTENT '
434
 
                                'FILE_A FILE_B ANOTHER_NONEXISTENT '
435
 
                                'FILE_C FILE_D FILE_E', retcode=3)
436
 
        self.assertEqual(expected, out.splitlines(True))
437
 
        self.assertContainsRe(err,
438
 
                              r'.*ERROR: Path\(s\) do not exist: '
439
 
                              'ANOTHER_NONEXISTENT NONEXISTENT.*')
440
 
        expected = [
441
 
            ' M  FILE_B\n',
442
 
            ' M  FILE_C\n',
443
 
            ' D  FILE_E\n',
444
 
            'X   ANOTHER_NONEXISTENT\n',
445
 
            'X   NONEXISTENT\n',
446
 
            ]
447
 
        out, err = self.run_bzr('status --short NONEXISTENT '
448
 
                                'FILE_A FILE_B ANOTHER_NONEXISTENT '
449
 
                                'FILE_C FILE_D FILE_E', retcode=3)
450
 
        self.assertEqual(expected, out.splitlines(True))
451
 
        self.assertContainsRe(err,
452
 
                              r'.*ERROR: Path\(s\) do not exist: '
453
 
                              'ANOTHER_NONEXISTENT NONEXISTENT.*')
454
 
 
455
 
    def test_status_nonexistent_file_with_unversioned(self):
456
 
        # brz st [--short] NONEXISTENT A B UNVERSIONED_BUT_EXISTING C D E Q
457
 
        wt = self._prepare_nonexistent()
458
 
        expected = [
459
 
            'removed:\n',
460
 
            '  FILE_E\n',
461
 
            'added:\n',
462
 
            '  FILE_Q\n',
463
 
            'modified:\n',
464
 
            '  FILE_B\n',
465
 
            '  FILE_C\n',
466
 
            'unknown:\n',
467
 
            '  UNVERSIONED_BUT_EXISTING\n',
468
 
            'nonexistent:\n',
469
 
            '  NONEXISTENT\n',
470
 
            ]
471
 
        out, err = self.run_bzr('status NONEXISTENT '
472
 
                                'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
473
 
                                'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
474
 
        self.assertEqual(expected, out.splitlines(True))
475
 
        self.assertContainsRe(err,
476
 
                              r'.*ERROR: Path\(s\) do not exist: '
477
 
                              'NONEXISTENT.*')
478
 
        expected = sorted([
479
 
            '+N  FILE_Q\n',
480
 
            '?   UNVERSIONED_BUT_EXISTING\n',
481
 
            ' D  FILE_E\n',
482
 
            ' M  FILE_C\n',
483
 
            ' M  FILE_B\n',
484
 
            'X   NONEXISTENT\n',
485
 
            ])
486
 
        out, err = self.run_bzr('status --short NONEXISTENT '
487
 
                                'FILE_A FILE_B UNVERSIONED_BUT_EXISTING '
488
 
                                'FILE_C FILE_D FILE_E FILE_Q', retcode=3)
489
 
        actual = out.splitlines(True)
490
 
        actual.sort()
491
 
        self.assertEqual(expected, actual)
492
 
        self.assertContainsRe(err,
493
 
                              r'.*ERROR: Path\(s\) do not exist: '
494
 
                              'NONEXISTENT.*')
495
 
 
496
 
    def test_status_out_of_date(self):
497
 
        """Simulate status of out-of-date tree after remote push"""
498
 
        tree = self.make_branch_and_tree('.')
499
 
        self.build_tree_contents([('a', b'foo\n')])
500
 
        with tree.lock_write():
501
 
            tree.add(['a'])
502
 
            tree.commit('add test file')
503
 
            # simulate what happens after a remote push
504
 
            tree.set_last_revision(b"0")
505
 
        out, err = self.run_bzr('status')
506
 
        self.assertEqual("working tree is out of date, run 'brz update'\n",
507
 
                         err)
508
 
 
509
 
    def test_status_on_ignored(self):
510
 
        """Tests branch status on an unversioned file which is considered ignored.
511
 
 
512
 
        See https://bugs.launchpad.net/bzr/+bug/40103
513
 
        """
514
 
        tree = self.make_branch_and_tree('.')
515
 
 
516
 
        self.build_tree(['test1.c', 'test1.c~', 'test2.c~'])
517
 
        result = self.run_bzr('status')[0]
518
 
        self.assertContainsRe(result, "unknown:\n  test1.c\n")
519
 
        short_result = self.run_bzr('status --short')[0]
520
 
        self.assertContainsRe(short_result, "\\?   test1.c\n")
521
 
 
522
 
        result = self.run_bzr('status test1.c')[0]
523
 
        self.assertContainsRe(result, "unknown:\n  test1.c\n")
524
 
        short_result = self.run_bzr('status --short test1.c')[0]
525
 
        self.assertContainsRe(short_result, "\\?   test1.c\n")
526
 
 
527
 
        result = self.run_bzr('status test1.c~')[0]
528
 
        self.assertContainsRe(result, "ignored:\n  test1.c~\n")
529
 
        short_result = self.run_bzr('status --short test1.c~')[0]
530
 
        self.assertContainsRe(short_result, "I   test1.c~\n")
531
 
 
532
 
        result = self.run_bzr('status test1.c~ test2.c~')[0]
533
 
        self.assertContainsRe(result, "ignored:\n  test1.c~\n  test2.c~\n")
534
 
        short_result = self.run_bzr('status --short test1.c~ test2.c~')[0]
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]
538
 
        self.assertContainsRe(
539
 
            result, "unknown:\n  test1.c\nignored:\n  test1.c~\n  test2.c~\n")
540
 
        short_result = self.run_bzr(
541
 
            'status --short test1.c test1.c~ test2.c~')[0]
542
 
        self.assertContainsRe(
543
 
            short_result, "\\?   test1.c\nI   test1.c~\nI   test2.c~\n")
544
 
 
545
 
    def test_status_write_lock(self):
546
 
        """Test that status works without fetching history and
547
 
        having a write lock.
548
 
 
549
 
        See https://bugs.launchpad.net/bzr/+bug/149270
550
 
        """
551
 
        mkdir('branch1')
552
 
        wt = self.make_branch_and_tree('branch1')
553
 
        b = wt.branch
554
 
        wt.commit('Empty commit 1')
555
 
        wt2 = b.controldir.sprout('branch2').open_workingtree()
556
 
        wt2.commit('Empty commit 2')
557
 
        out, err = self.run_bzr('status branch1 -rbranch:branch2')
558
 
        self.assertEqual('', out)
559
 
 
560
 
    def test_status_with_shelves(self):
561
 
        """Ensure that _show_shelve_summary handler works.
562
 
        """
563
 
        wt = self.make_branch_and_tree('.')
564
 
        self.build_tree(['hello.c'])
565
 
        wt.add('hello.c')
566
 
        self.run_bzr(['shelve', '--all', '-m', 'foo'])
567
 
        self.build_tree(['bye.c'])
568
 
        wt.add('bye.c')
569
 
        self.assertStatus([
570
 
            'added:\n',
571
 
            '  bye.c\n',
572
 
            '1 shelf exists. See "brz shelve --list" for details.\n',
573
 
            ],
574
 
            wt)
575
 
        self.run_bzr(['shelve', '--all', '-m', 'bar'])
576
 
        self.build_tree(['eggs.c', 'spam.c'])
577
 
        wt.add('eggs.c')
578
 
        wt.add('spam.c')
579
 
        self.assertStatus([
580
 
            'added:\n',
581
 
            '  eggs.c\n',
582
 
            '  spam.c\n',
583
 
            '2 shelves exist. See "brz shelve --list" for details.\n',
584
 
            ],
585
 
            wt)
586
 
        self.assertStatus([
587
 
            'added:\n',
588
 
            '  spam.c\n',
589
 
            ],
590
 
            wt,
591
 
            specific_files=['spam.c'])
592
 
 
593
 
 
594
 
class CheckoutStatus(BranchStatus):
595
 
 
596
 
    def setUp(self):
597
 
        super(CheckoutStatus, self).setUp()
598
 
        mkdir('codir')
599
 
        chdir('codir')
600
 
 
601
 
    def make_branch_and_tree(self, relpath):
602
 
        source = self.make_branch(pathjoin('..', relpath))
603
 
        checkout = bzrdir.BzrDirMetaFormat1().initialize(relpath)
604
 
        checkout.set_branch_reference(source)
605
 
        return checkout.create_workingtree()
606
 
 
607
 
 
608
 
class TestStatus(TestCaseWithTransport):
609
 
 
610
 
    def test_status_plain(self):
611
 
        tree = self.make_branch_and_tree('.')
612
 
 
613
 
        self.build_tree(['hello.txt'])
614
 
        result = self.run_bzr("status")[0]
615
 
        self.assertContainsRe(result, "unknown:\n  hello.txt\n")
616
 
 
617
 
        tree.add("hello.txt")
618
 
        result = self.run_bzr("status")[0]
619
 
        self.assertContainsRe(result, "added:\n  hello.txt\n")
620
 
 
621
 
        tree.commit(message="added")
622
 
        result = self.run_bzr("status -r 0..1")[0]
623
 
        self.assertContainsRe(result, "added:\n  hello.txt\n")
624
 
 
625
 
        result = self.run_bzr("status -c 1")[0]
626
 
        self.assertContainsRe(result, "added:\n  hello.txt\n")
627
 
 
628
 
        self.build_tree(['world.txt'])
629
 
        result = self.run_bzr("status -r 0")[0]
630
 
        self.assertContainsRe(result, "added:\n  hello.txt\n"
631
 
                                      "unknown:\n  world.txt\n")
632
 
        result2 = self.run_bzr("status -r 0..")[0]
633
 
        self.assertEqual(result2, result)
634
 
 
635
 
    def test_status_short(self):
636
 
        tree = self.make_branch_and_tree('.')
637
 
 
638
 
        self.build_tree(['hello.txt'])
639
 
        result = self.run_bzr("status --short")[0]
640
 
        self.assertContainsRe(result, "[?]   hello.txt\n")
641
 
 
642
 
        tree.add("hello.txt")
643
 
        result = self.run_bzr("status --short")[0]
644
 
        self.assertContainsRe(result, "[+]N  hello.txt\n")
645
 
 
646
 
        tree.commit(message="added")
647
 
        result = self.run_bzr("status --short -r 0..1")[0]
648
 
        self.assertContainsRe(result, "[+]N  hello.txt\n")
649
 
 
650
 
        self.build_tree(['world.txt'])
651
 
        result = self.run_bzr("status -S -r 0")[0]
652
 
        self.assertContainsRe(result, "[+]N  hello.txt\n"
653
 
                                      "[?]   world.txt\n")
654
 
        result2 = self.run_bzr("status -S -r 0..")[0]
655
 
        self.assertEqual(result2, result)
656
 
 
657
 
    def test_status_versioned(self):
658
 
        tree = self.make_branch_and_tree('.')
659
 
 
660
 
        self.build_tree(['hello.txt'])
661
 
        result = self.run_bzr("status --versioned")[0]
662
 
        self.assertNotContainsRe(result, "unknown:\n  hello.txt\n")
663
 
 
664
 
        tree.add("hello.txt")
665
 
        result = self.run_bzr("status --versioned")[0]
666
 
        self.assertContainsRe(result, "added:\n  hello.txt\n")
667
 
 
668
 
        tree.commit("added")
669
 
        result = self.run_bzr("status --versioned -r 0..1")[0]
670
 
        self.assertContainsRe(result, "added:\n  hello.txt\n")
671
 
 
672
 
        self.build_tree(['world.txt'])
673
 
        result = self.run_bzr("status --versioned -r 0")[0]
674
 
        self.assertContainsRe(result, "added:\n  hello.txt\n")
675
 
        self.assertNotContainsRe(result, "unknown:\n  world.txt\n")
676
 
        result2 = self.run_bzr("status --versioned -r 0..")[0]
677
 
        self.assertEqual(result2, result)
678
 
 
679
 
    def test_status_SV(self):
680
 
        tree = self.make_branch_and_tree('.')
681
 
 
682
 
        self.build_tree(['hello.txt'])
683
 
        result = self.run_bzr("status -SV")[0]
684
 
        self.assertNotContainsRe(result, "hello.txt")
685
 
 
686
 
        tree.add("hello.txt")
687
 
        result = self.run_bzr("status -SV")[0]
688
 
        self.assertContainsRe(result, "[+]N  hello.txt\n")
689
 
 
690
 
        tree.commit(message="added")
691
 
        result = self.run_bzr("status -SV -r 0..1")[0]
692
 
        self.assertContainsRe(result, "[+]N  hello.txt\n")
693
 
 
694
 
        self.build_tree(['world.txt'])
695
 
        result = self.run_bzr("status -SV -r 0")[0]
696
 
        self.assertContainsRe(result, "[+]N  hello.txt\n")
697
 
 
698
 
        result2 = self.run_bzr("status -SV -r 0..")[0]
699
 
        self.assertEqual(result2, result)
700
 
 
701
 
    def assertStatusContains(self, pattern, short=False):
702
 
        """Run status, and assert it contains the given pattern"""
703
 
        if short:
704
 
            result = self.run_bzr("status --short")[0]
705
 
        else:
706
 
            result = self.run_bzr("status")[0]
707
 
        self.assertContainsRe(result, pattern)
708
 
 
709
 
    def test_kind_change_plain(self):
710
 
        tree = self.make_branch_and_tree('.')
711
 
        self.build_tree(['file'])
712
 
        tree.add('file')
713
 
        tree.commit('added file')
714
 
        unlink('file')
715
 
        self.build_tree(['file/'])
716
 
        self.assertStatusContains(
717
 
            'kind changed:\n  file \\(file => directory\\)')
718
 
        tree.rename_one('file', 'directory')
719
 
        self.assertStatusContains('renamed:\n  file => directory/\n'
720
 
                                  'modified:\n  directory/\n')
721
 
        rmdir('directory')
722
 
        self.assertStatusContains('removed:\n  file\n')
723
 
 
724
 
    def test_kind_change_short(self):
725
 
        tree = self.make_branch_and_tree('.')
726
 
        self.build_tree(['file'])
727
 
        tree.add('file')
728
 
        tree.commit('added file')
729
 
        unlink('file')
730
 
        self.build_tree(['file/'])
731
 
        self.assertStatusContains('K  file => file/',
732
 
                                  short=True)
733
 
        tree.rename_one('file', 'directory')
734
 
        self.assertStatusContains('RK  file => directory/',
735
 
                                  short=True)
736
 
        rmdir('directory')
737
 
        self.assertStatusContains('RD  file => directory',
738
 
                                  short=True)
739
 
 
740
 
    def test_status_illegal_revision_specifiers(self):
741
 
        out, err = self.run_bzr('status -r 1..23..123', retcode=3)
742
 
        self.assertContainsRe(err, 'one or two revision specifiers')
743
 
 
744
 
    def test_status_no_pending(self):
745
 
        a_tree = self.make_branch_and_tree('a')
746
 
        self.build_tree(['a/a'])
747
 
        a_tree.add('a')
748
 
        a_tree.commit('a')
749
 
        b_tree = a_tree.controldir.sprout('b').open_workingtree()
750
 
        self.build_tree(['b/b'])
751
 
        b_tree.add('b')
752
 
        b_tree.commit('b')
753
 
 
754
 
        self.run_bzr('merge ../b', working_dir='a')
755
 
        out, err = self.run_bzr('status --no-pending', working_dir='a')
756
 
        self.assertEqual(out, "added:\n  b\n")
757
 
 
758
 
    def test_pending_specific_files(self):
759
 
        """With a specific file list, pending merges are not shown."""
760
 
        tree = self.make_branch_and_tree('tree')
761
 
        self.build_tree_contents([('tree/a', b'content of a\n')])
762
 
        tree.add('a')
763
 
        r1_id = tree.commit('one')
764
 
        alt = tree.controldir.sprout('alt').open_workingtree()
765
 
        self.build_tree_contents([('alt/a', b'content of a\nfrom alt\n')])
766
 
        alt_id = alt.commit('alt')
767
 
        tree.merge_from_branch(alt.branch)
768
 
        output = self.make_utf8_encoded_stringio()
769
 
        show_tree_status(tree, to_file=output)
770
 
        self.assertContainsRe(output.getvalue(), b'pending merge')
771
 
        out, err = self.run_bzr('status tree/a')
772
 
        self.assertNotContainsRe(out, 'pending merge')
773
 
 
774
 
 
775
 
class TestStatusEncodings(TestCaseWithTransport):
776
 
 
777
 
    def make_uncommitted_tree(self):
778
 
        """Build a branch with uncommitted unicode named changes in the cwd."""
779
 
        working_tree = self.make_branch_and_tree(u'.')
780
 
        filename = u'hell\u00d8'
781
 
        try:
782
 
            self.build_tree_contents([(filename, b'contents of hello')])
783
 
        except UnicodeEncodeError:
784
 
            raise TestSkipped("can't build unicode working tree in "
785
 
                              "filesystem encoding %s" % sys.getfilesystemencoding())
786
 
        working_tree.add(filename)
787
 
        return working_tree
788
 
 
789
 
    def test_stdout_ascii(self):
790
 
        self.overrideAttr(osutils, '_cached_user_encoding', 'ascii')
791
 
        working_tree = self.make_uncommitted_tree()
792
 
        stdout, stderr = self.run_bzr("status")
793
 
 
794
 
        self.assertEqual(stdout, """\
795
 
added:
796
 
  hell?
797
 
""")
798
 
 
799
 
    def test_stdout_latin1(self):
800
 
        self.overrideAttr(osutils, '_cached_user_encoding', 'latin-1')
801
 
        working_tree = self.make_uncommitted_tree()
802
 
        stdout, stderr = self.run_bzr('status')
803
 
 
804
 
        expected = u"""\
805
 
added:
806
 
  hell\u00d8
807
 
"""
808
 
        if not PY3:
809
 
            expected = expected.encode('latin-1')
810
 
        self.assertEqual(stdout, expected)
 
128
        from cStringIO import StringIO
 
129
        from bzrlib.status import show_status
 
130
        from bzrlib.branch import Branch
 
131
        
 
132
        b = Branch.initialize('.')
 
133
 
 
134
        self.build_tree(['directory/','directory/hello.c', 'bye.c','test.c','dir2/'])
 
135
        b.add('directory')
 
136
        b.add('test.c')
 
137
        b.working_tree().commit('testing')
 
138
        
 
139
        tof = StringIO()
 
140
        show_status(b, to_file=tof)
 
141
        tof.seek(0)
 
142
        self.assertEquals(tof.readlines(),
 
143
                          ['unknown:\n',
 
144
                           '  bye.c\n',
 
145
                           '  dir2\n',
 
146
                           '  directory/hello.c\n'
 
147
                           ])
 
148
 
 
149
        tof = StringIO()
 
150
        show_status(b, specific_files=['bye.c','test.c','absent.c'], to_file=tof)
 
151
        tof.seek(0)
 
152
        self.assertEquals(tof.readlines(),
 
153
                          ['unknown:\n',
 
154
                           '  bye.c\n'
 
155
                           ])
 
156
        
 
157
        tof = StringIO()
 
158
        show_status(b, specific_files=['directory'], to_file=tof)
 
159
        tof.seek(0)
 
160
        self.assertEquals(tof.readlines(),
 
161
                          ['unknown:\n',
 
162
                           '  directory/hello.c\n'
 
163
                           ])
 
164
        tof = StringIO()
 
165
        show_status(b, specific_files=['dir2'], to_file=tof)
 
166
        tof.seek(0)
 
167
        self.assertEquals(tof.readlines(),
 
168
                          ['unknown:\n',
 
169
                           '  dir2\n'
 
170
                           ])