/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 breezy/tests/blackbox/test_status.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-08-23 01:15:41 UTC
  • mfrom: (7520.1.4 merge-3.1)
  • Revision ID: breezy.the.bot@gmail.com-20200823011541-nv0oh7nzaganx2qy
Merge lp:brz/3.1.

Merged from https://code.launchpad.net/~jelmer/brz/merge-3.1/+merge/389690

Show diffs side-by-side

added added

removed removed

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