/brz/remove-bazaar

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

« back to all changes in this revision

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

  • Committer: Andrew Bennetts
  • Date: 2008-09-08 12:59:00 UTC
  • mfrom: (3695 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3756.
  • Revision ID: andrew.bennetts@canonical.com-20080908125900-8ywtsr7jqyyatjz0
Merge from bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""Tests of status command.
 
18
 
 
19
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
"""
 
24
 
 
25
from cStringIO import StringIO
 
26
import codecs
 
27
from os import mkdir, chdir, rmdir, unlink
 
28
import sys
 
29
from tempfile import TemporaryFile
 
30
 
 
31
from bzrlib import (
 
32
    bzrdir,
 
33
    conflicts,
 
34
    errors,
 
35
    osutils,
 
36
    )
 
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
 
43
 
 
44
 
 
45
class BranchStatus(TestCaseWithTransport):
 
46
    
 
47
    def assertStatus(self, expected_lines, working_tree,
 
48
        revision=None, short=False, pending=True):
 
49
        """Run status in working_tree and look for output.
 
50
        
 
51
        :param expected_lines: The lines to look for.
 
52
        :param working_tree: The tree to run status in.
 
53
        """
 
54
        output_string = self.status_string(working_tree, revision, short,
 
55
                pending)
 
56
        self.assertEqual(expected_lines, output_string.splitlines(True))
 
57
    
 
58
    def status_string(self, wt, revision=None, short=False, pending=True):
 
59
        # use a real file rather than StringIO because it doesn't handle
 
60
        # Unicode very well.
 
61
        tof = codecs.getwriter('utf-8')(TemporaryFile())
 
62
        show_tree_status(wt, to_file=tof, revision=revision, short=short,
 
63
                show_pending=pending)
 
64
        tof.seek(0)
 
65
        return tof.read().decode('utf-8')
 
66
 
 
67
    def test_branch_status(self):
 
68
        """Test basic branch status"""
 
69
        wt = self.make_branch_and_tree('.')
 
70
 
 
71
        # status with no commits or files - it must
 
72
        # work and show no output. We do this with no
 
73
        # commits to be sure that it's not going to fail
 
74
        # as a corner case.
 
75
        self.assertStatus([], wt)
 
76
 
 
77
        self.build_tree(['hello.c', 'bye.c'])
 
78
        self.assertStatus([
 
79
                'unknown:\n',
 
80
                '  bye.c\n',
 
81
                '  hello.c\n',
 
82
            ],
 
83
            wt)
 
84
        self.assertStatus([
 
85
                '?   bye.c\n',
 
86
                '?   hello.c\n',
 
87
            ],
 
88
            wt, short=True)
 
89
 
 
90
        # add a commit to allow showing pending merges.
 
91
        wt.commit('create a parent to allow testing merge output')
 
92
 
 
93
        wt.add_parent_tree_id('pending@pending-0-0')
 
94
        self.assertStatus([
 
95
                'unknown:\n',
 
96
                '  bye.c\n',
 
97
                '  hello.c\n',
 
98
                'pending merges:\n',
 
99
                '  (ghost) pending@pending-0-0\n',
 
100
            ],
 
101
            wt)
 
102
        self.assertStatus([
 
103
                '?   bye.c\n',
 
104
                '?   hello.c\n',
 
105
                'P   (ghost) pending@pending-0-0\n',
 
106
            ],
 
107
            wt, short=True)
 
108
        self.assertStatus([
 
109
                'unknown:\n',
 
110
                '  bye.c\n',
 
111
                '  hello.c\n',
 
112
            ],
 
113
            wt, pending=False)
 
114
        self.assertStatus([
 
115
                '?   bye.c\n',
 
116
                '?   hello.c\n',
 
117
            ],
 
118
            wt, short=True, pending=False)
 
119
 
 
120
    def test_branch_status_revisions(self):
 
121
        """Tests branch status with revisions"""
 
122
        wt = self.make_branch_and_tree('.')
 
123
 
 
124
        self.build_tree(['hello.c', 'bye.c'])
 
125
        wt.add('hello.c')
 
126
        wt.add('bye.c')
 
127
        wt.commit('Test message')
 
128
 
 
129
        revs = [RevisionSpec.from_string('0')]
 
130
        self.assertStatus([
 
131
                'added:\n',
 
132
                '  bye.c\n',
 
133
                '  hello.c\n'
 
134
            ],
 
135
            wt,
 
136
            revision=revs)
 
137
 
 
138
        self.build_tree(['more.c'])
 
139
        wt.add('more.c')
 
140
        wt.commit('Another test message')
 
141
        
 
142
        revs.append(RevisionSpec.from_string('1'))
 
143
        self.assertStatus([
 
144
                'added:\n',
 
145
                '  bye.c\n',
 
146
                '  hello.c\n',
 
147
            ],
 
148
            wt,
 
149
            revision=revs)
 
150
 
 
151
    def test_pending(self):
 
152
        """Pending merges display works, including Unicode"""
 
153
        mkdir("./branch")
 
154
        wt = self.make_branch_and_tree('branch')
 
155
        b = wt.branch
 
156
        wt.commit("Empty commit 1")
 
157
        b_2_dir = b.bzrdir.sprout('./copy')
 
158
        b_2 = b_2_dir.open_branch()
 
159
        wt2 = b_2_dir.open_workingtree()
 
160
        wt.commit(u"\N{TIBETAN DIGIT TWO} Empty commit 2")
 
161
        wt2.merge_from_branch(wt.branch)
 
162
        message = self.status_string(wt2)
 
163
        self.assertStartsWith(message, "pending merges:\n")
 
164
        self.assertEndsWith(message, "Empty commit 2\n")
 
165
        wt2.commit("merged")
 
166
        # must be long to make sure we see elipsis at the end
 
167
        wt.commit("Empty commit 3 " +
 
168
                   "blah blah blah blah " * 100)
 
169
        wt2.merge_from_branch(wt.branch)
 
170
        message = self.status_string(wt2)
 
171
        self.assertStartsWith(message, "pending merges:\n")
 
172
        self.assert_("Empty commit 3" in message)
 
173
        self.assertEndsWith(message, "...\n")
 
174
 
 
175
    def test_tree_status_ignores(self):
 
176
        """Tests branch status with ignores"""
 
177
        wt = self.make_branch_and_tree('.')
 
178
        self.run_bzr('ignore *~')
 
179
        wt.commit('commit .bzrignore')
 
180
        self.build_tree(['foo.c', 'foo.c~'])
 
181
        self.assertStatus([
 
182
                'unknown:\n',
 
183
                '  foo.c\n',
 
184
                ],
 
185
                wt)
 
186
        self.assertStatus([
 
187
                '?   foo.c\n',
 
188
                ],
 
189
                wt, short=True)
 
190
 
 
191
    def test_tree_status_specific_files(self):
 
192
        """Tests branch status with given specific files"""
 
193
        wt = self.make_branch_and_tree('.')
 
194
        b = wt.branch
 
195
 
 
196
        self.build_tree(['directory/','directory/hello.c', 'bye.c','test.c','dir2/'])
 
197
        wt.add('directory')
 
198
        wt.add('test.c')
 
199
        wt.commit('testing')
 
200
        
 
201
        self.assertStatus([
 
202
                'unknown:\n',
 
203
                '  bye.c\n',
 
204
                '  dir2/\n',
 
205
                '  directory/hello.c\n'
 
206
                ],
 
207
                wt)
 
208
 
 
209
        self.assertStatus([
 
210
                '?   bye.c\n',
 
211
                '?   dir2/\n',
 
212
                '?   directory/hello.c\n'
 
213
                ],
 
214
                wt, short=True)
 
215
 
 
216
        tof = StringIO()
 
217
        self.assertRaises(errors.PathsDoNotExist,
 
218
                          show_tree_status,
 
219
                          wt, specific_files=['bye.c','test.c','absent.c'], 
 
220
                          to_file=tof)
 
221
        
 
222
        tof = StringIO()
 
223
        show_tree_status(wt, specific_files=['directory'], to_file=tof)
 
224
        tof.seek(0)
 
225
        self.assertEquals(tof.readlines(),
 
226
                          ['unknown:\n',
 
227
                           '  directory/hello.c\n'
 
228
                           ])
 
229
        tof = StringIO()
 
230
        show_tree_status(wt, specific_files=['directory'], to_file=tof,
 
231
                         short=True)
 
232
        tof.seek(0)
 
233
        self.assertEquals(tof.readlines(), ['?   directory/hello.c\n'])
 
234
 
 
235
        tof = StringIO()
 
236
        show_tree_status(wt, specific_files=['dir2'], to_file=tof)
 
237
        tof.seek(0)
 
238
        self.assertEquals(tof.readlines(),
 
239
                          ['unknown:\n',
 
240
                           '  dir2/\n'
 
241
                           ])
 
242
        tof = StringIO()
 
243
        show_tree_status(wt, specific_files=['dir2'], to_file=tof, short=True)
 
244
        tof.seek(0)
 
245
        self.assertEquals(tof.readlines(), ['?   dir2/\n'])
 
246
 
 
247
        tof = StringIO()
 
248
        revs = [RevisionSpec.from_string('0'), RevisionSpec.from_string('1')]
 
249
        show_tree_status(wt, specific_files=['test.c'], to_file=tof,
 
250
                         short=True, revision=revs)
 
251
        tof.seek(0)
 
252
        self.assertEquals(tof.readlines(), ['+N  test.c\n'])
 
253
 
 
254
    def test_specific_files_conflicts(self):
 
255
        tree = self.make_branch_and_tree('.')
 
256
        self.build_tree(['dir2/'])
 
257
        tree.add('dir2')
 
258
        tree.commit('added dir2')
 
259
        tree.set_conflicts(conflicts.ConflictList(
 
260
            [conflicts.ContentsConflict('foo')]))
 
261
        tof = StringIO()
 
262
        show_tree_status(tree, specific_files=['dir2'], to_file=tof)
 
263
        self.assertEqualDiff('', tof.getvalue())
 
264
        tree.set_conflicts(conflicts.ConflictList(
 
265
            [conflicts.ContentsConflict('dir2')]))
 
266
        tof = StringIO()
 
267
        show_tree_status(tree, specific_files=['dir2'], to_file=tof)
 
268
        self.assertEqualDiff('conflicts:\n  Contents conflict in dir2\n',
 
269
                             tof.getvalue())
 
270
 
 
271
        tree.set_conflicts(conflicts.ConflictList(
 
272
            [conflicts.ContentsConflict('dir2/file1')]))
 
273
        tof = StringIO()
 
274
        show_tree_status(tree, specific_files=['dir2'], to_file=tof)
 
275
        self.assertEqualDiff('conflicts:\n  Contents conflict in dir2/file1\n',
 
276
                             tof.getvalue())
 
277
 
 
278
    def test_status_nonexistent_file(self):
 
279
        # files that don't exist in either the basis tree or working tree
 
280
        # should give an error
 
281
        wt = self.make_branch_and_tree('.')
 
282
        out, err = self.run_bzr('status does-not-exist', retcode=3)
 
283
        self.assertContainsRe(err, r'do not exist.*does-not-exist')
 
284
 
 
285
    def test_status_out_of_date(self):
 
286
        """Simulate status of out-of-date tree after remote push"""
 
287
        tree = self.make_branch_and_tree('.')
 
288
        self.build_tree_contents([('a', 'foo\n')])
 
289
        tree.lock_write()
 
290
        try:
 
291
            tree.add(['a'])
 
292
            tree.commit('add test file')
 
293
            # simulate what happens after a remote push
 
294
            tree.set_last_revision("0")
 
295
        finally:
 
296
            # before run another commands we should unlock tree
 
297
            tree.unlock()
 
298
        out, err = self.run_bzr('status')
 
299
        self.assertEqual("working tree is out of date, run 'bzr update'\n",
 
300
                         err)
 
301
 
 
302
 
 
303
class CheckoutStatus(BranchStatus):
 
304
 
 
305
    def setUp(self):
 
306
        super(CheckoutStatus, self).setUp()
 
307
        mkdir('codir')
 
308
        chdir('codir')
 
309
        
 
310
    def make_branch_and_tree(self, relpath):
 
311
        source = self.make_branch(pathjoin('..', relpath))
 
312
        checkout = bzrdir.BzrDirMetaFormat1().initialize(relpath)
 
313
        bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
 
314
        return checkout.create_workingtree()
 
315
 
 
316
 
 
317
class TestStatus(TestCaseWithTransport):
 
318
 
 
319
    def test_status_plain(self):
 
320
        tree = self.make_branch_and_tree('.')
 
321
 
 
322
        self.build_tree(['hello.txt'])
 
323
        result = self.run_bzr("status")[0]
 
324
        self.assertContainsRe(result, "unknown:\n  hello.txt\n")
 
325
 
 
326
        tree.add("hello.txt")
 
327
        result = self.run_bzr("status")[0]
 
328
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
329
 
 
330
        tree.commit(message="added")
 
331
        result = self.run_bzr("status -r 0..1")[0]
 
332
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
333
 
 
334
        result = self.run_bzr("status -c 1")[0]
 
335
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
336
 
 
337
        self.build_tree(['world.txt'])
 
338
        result = self.run_bzr("status -r 0")[0]
 
339
        self.assertContainsRe(result, "added:\n  hello.txt\n" \
 
340
                                      "unknown:\n  world.txt\n")
 
341
        result2 = self.run_bzr("status -r 0..")[0]
 
342
        self.assertEquals(result2, result)
 
343
 
 
344
    def test_status_short(self):
 
345
        tree = self.make_branch_and_tree('.')
 
346
 
 
347
        self.build_tree(['hello.txt'])
 
348
        result = self.run_bzr("status --short")[0]
 
349
        self.assertContainsRe(result, "[?]   hello.txt\n")
 
350
 
 
351
        tree.add("hello.txt")
 
352
        result = self.run_bzr("status --short")[0]
 
353
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
354
 
 
355
        tree.commit(message="added")
 
356
        result = self.run_bzr("status --short -r 0..1")[0]
 
357
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
358
 
 
359
        self.build_tree(['world.txt'])
 
360
        result = self.run_bzr("status --short -r 0")[0]
 
361
        self.assertContainsRe(result, "[+]N  hello.txt\n" \
 
362
                                      "[?]   world.txt\n")
 
363
        result2 = self.run_bzr("status --short -r 0..")[0]
 
364
        self.assertEquals(result2, result)
 
365
 
 
366
    def test_status_versioned(self):
 
367
        tree = self.make_branch_and_tree('.')
 
368
 
 
369
        self.build_tree(['hello.txt'])
 
370
        result = self.run_bzr("status --versioned")[0]
 
371
        self.assertNotContainsRe(result, "unknown:\n  hello.txt\n")
 
372
 
 
373
        tree.add("hello.txt")
 
374
        result = self.run_bzr("status --versioned")[0]
 
375
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
376
 
 
377
        tree.commit("added")
 
378
        result = self.run_bzr("status --versioned -r 0..1")[0]
 
379
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
380
 
 
381
        self.build_tree(['world.txt'])
 
382
        result = self.run_bzr("status --versioned -r 0")[0]
 
383
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
384
        self.assertNotContainsRe(result, "unknown:\n  world.txt\n")
 
385
        result2 = self.run_bzr("status --versioned -r 0..")[0]
 
386
        self.assertEquals(result2, result)
 
387
 
 
388
    def test_status_SV(self):
 
389
        tree = self.make_branch_and_tree('.')
 
390
 
 
391
        self.build_tree(['hello.txt'])
 
392
        result = self.run_bzr("status -SV")[0]
 
393
        self.assertNotContainsRe(result, "hello.txt")
 
394
 
 
395
        tree.add("hello.txt")
 
396
        result = self.run_bzr("status -SV")[0]
 
397
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
398
 
 
399
        tree.commit(message="added")
 
400
        result = self.run_bzr("status -SV -r 0..1")[0]
 
401
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
402
 
 
403
        self.build_tree(['world.txt'])
 
404
        result = self.run_bzr("status -SV -r 0")[0]
 
405
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
406
 
 
407
        result2 = self.run_bzr("status -SV -r 0..")[0]
 
408
        self.assertEquals(result2, result)
 
409
 
 
410
    def assertStatusContains(self, pattern):
 
411
        """Run status, and assert it contains the given pattern"""
 
412
        result = self.run_bzr("status --short")[0]
 
413
        self.assertContainsRe(result, pattern)
 
414
 
 
415
    def test_kind_change_short(self):
 
416
        tree = self.make_branch_and_tree('.')
 
417
        self.build_tree(['file'])
 
418
        tree.add('file')
 
419
        tree.commit('added file')
 
420
        unlink('file')
 
421
        self.build_tree(['file/'])
 
422
        self.assertStatusContains('K  file => file/')
 
423
        tree.rename_one('file', 'directory')
 
424
        self.assertStatusContains('RK  file => directory/')
 
425
        rmdir('directory')
 
426
        self.assertStatusContains('RD  file => directory')
 
427
 
 
428
    def test_status_illegal_revision_specifiers(self):
 
429
        out, err = self.run_bzr('status -r 1..23..123', retcode=3)
 
430
        self.assertContainsRe(err, 'one or two revision specifiers')
 
431
 
 
432
    def test_status_no_pending(self):
 
433
        a_tree = self.make_branch_and_tree('a')
 
434
        self.build_tree(['a/a'])
 
435
        a_tree.add('a')
 
436
        a_tree.commit('a')
 
437
        b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
 
438
        self.build_tree(['b/b'])
 
439
        b_tree.add('b')
 
440
        b_tree.commit('b')
 
441
 
 
442
        self.run_bzr('merge ../b', working_dir='a')
 
443
        out, err = self.run_bzr('status --no-pending', working_dir='a')
 
444
        self.assertEquals(out, "added:\n  b\n")
 
445
 
 
446
    def test_pending_specific_files(self):
 
447
        """With a specific file list, pending merges are not shown."""
 
448
        tree = self.make_branch_and_tree('tree')
 
449
        self.build_tree_contents([('tree/a', 'content of a\n')])
 
450
        tree.add('a')
 
451
        r1_id = tree.commit('one')
 
452
        alt = tree.bzrdir.sprout('alt').open_workingtree()
 
453
        self.build_tree_contents([('alt/a', 'content of a\nfrom alt\n')])
 
454
        alt_id = alt.commit('alt')
 
455
        tree.merge_from_branch(alt.branch)
 
456
        output = self.make_utf8_encoded_stringio()
 
457
        show_tree_status(tree, to_file=output)
 
458
        self.assertContainsRe(output.getvalue(), 'pending merges:')
 
459
        out, err = self.run_bzr('status tree/a')
 
460
        self.assertNotContainsRe(out, 'pending merges:')
 
461
 
 
462
 
 
463
class TestStatusEncodings(TestCaseWithTransport):
 
464
    
 
465
    def setUp(self):
 
466
        TestCaseWithTransport.setUp(self)
 
467
        self.user_encoding = osutils._cached_user_encoding
 
468
        self.stdout = sys.stdout
 
469
 
 
470
    def tearDown(self):
 
471
        bzrlib.user_encoding = self.user_encoding
 
472
        sys.stdout = self.stdout
 
473
        TestCaseWithTransport.tearDown(self)
 
474
 
 
475
    def make_uncommitted_tree(self):
 
476
        """Build a branch with uncommitted unicode named changes in the cwd."""
 
477
        working_tree = self.make_branch_and_tree(u'.')
 
478
        filename = u'hell\u00d8'
 
479
        try:
 
480
            self.build_tree_contents([(filename, 'contents of hello')])
 
481
        except UnicodeEncodeError:
 
482
            raise TestSkipped("can't build unicode working tree in "
 
483
                "filesystem encoding %s" % sys.getfilesystemencoding())
 
484
        working_tree.add(filename)
 
485
        return working_tree
 
486
 
 
487
    def test_stdout_ascii(self):
 
488
        sys.stdout = StringIO()
 
489
        osutils._cached_user_encoding = 'ascii'
 
490
        working_tree = self.make_uncommitted_tree()
 
491
        stdout, stderr = self.run_bzr("status")
 
492
 
 
493
        self.assertEquals(stdout, """\
 
494
added:
 
495
  hell?
 
496
""")
 
497
 
 
498
    def test_stdout_latin1(self):
 
499
        sys.stdout = StringIO()
 
500
        osutils._cached_user_encoding = 'latin-1'
 
501
        working_tree = self.make_uncommitted_tree()
 
502
        stdout, stderr = self.run_bzr('status')
 
503
 
 
504
        self.assertEquals(stdout, u"""\
 
505
added:
 
506
  hell\u00d8
 
507
""".encode('latin-1'))
 
508