~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-10-31 03:15:38 UTC
  • mfrom: (3806.1.1 contrib)
  • Revision ID: pqm@pqm.ubuntu.com-20081031031538-0ih0zi2owevf6fwu
Add contrib/bzr_ssh_path_limiter. (Andrew Bennetts)

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
    def test_status_write_lock(self):
 
303
        """Test that status works without fetching history and
 
304
        having a write lock.
 
305
 
 
306
        See https://bugs.launchpad.net/bzr/+bug/149270
 
307
        """
 
308
        mkdir('branch1')
 
309
        wt = self.make_branch_and_tree('branch1')
 
310
        b = wt.branch
 
311
        wt.commit('Empty commit 1')
 
312
        wt2 = b.bzrdir.sprout('branch2').open_workingtree()
 
313
        wt2.commit('Empty commit 2')
 
314
        out, err = self.run_bzr('status branch1 -rbranch:branch2')
 
315
        self.assertEqual('', out)
 
316
 
 
317
 
 
318
class CheckoutStatus(BranchStatus):
 
319
 
 
320
    def setUp(self):
 
321
        super(CheckoutStatus, self).setUp()
 
322
        mkdir('codir')
 
323
        chdir('codir')
 
324
        
 
325
    def make_branch_and_tree(self, relpath):
 
326
        source = self.make_branch(pathjoin('..', relpath))
 
327
        checkout = bzrdir.BzrDirMetaFormat1().initialize(relpath)
 
328
        bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
 
329
        return checkout.create_workingtree()
 
330
 
 
331
 
 
332
class TestStatus(TestCaseWithTransport):
 
333
 
 
334
    def test_status_plain(self):
 
335
        tree = self.make_branch_and_tree('.')
 
336
 
 
337
        self.build_tree(['hello.txt'])
 
338
        result = self.run_bzr("status")[0]
 
339
        self.assertContainsRe(result, "unknown:\n  hello.txt\n")
 
340
 
 
341
        tree.add("hello.txt")
 
342
        result = self.run_bzr("status")[0]
 
343
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
344
 
 
345
        tree.commit(message="added")
 
346
        result = self.run_bzr("status -r 0..1")[0]
 
347
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
348
 
 
349
        result = self.run_bzr("status -c 1")[0]
 
350
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
351
 
 
352
        self.build_tree(['world.txt'])
 
353
        result = self.run_bzr("status -r 0")[0]
 
354
        self.assertContainsRe(result, "added:\n  hello.txt\n" \
 
355
                                      "unknown:\n  world.txt\n")
 
356
        result2 = self.run_bzr("status -r 0..")[0]
 
357
        self.assertEquals(result2, result)
 
358
 
 
359
    def test_status_short(self):
 
360
        tree = self.make_branch_and_tree('.')
 
361
 
 
362
        self.build_tree(['hello.txt'])
 
363
        result = self.run_bzr("status --short")[0]
 
364
        self.assertContainsRe(result, "[?]   hello.txt\n")
 
365
 
 
366
        tree.add("hello.txt")
 
367
        result = self.run_bzr("status --short")[0]
 
368
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
369
 
 
370
        tree.commit(message="added")
 
371
        result = self.run_bzr("status --short -r 0..1")[0]
 
372
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
373
 
 
374
        self.build_tree(['world.txt'])
 
375
        result = self.run_bzr("status --short -r 0")[0]
 
376
        self.assertContainsRe(result, "[+]N  hello.txt\n" \
 
377
                                      "[?]   world.txt\n")
 
378
        result2 = self.run_bzr("status --short -r 0..")[0]
 
379
        self.assertEquals(result2, result)
 
380
 
 
381
    def test_status_versioned(self):
 
382
        tree = self.make_branch_and_tree('.')
 
383
 
 
384
        self.build_tree(['hello.txt'])
 
385
        result = self.run_bzr("status --versioned")[0]
 
386
        self.assertNotContainsRe(result, "unknown:\n  hello.txt\n")
 
387
 
 
388
        tree.add("hello.txt")
 
389
        result = self.run_bzr("status --versioned")[0]
 
390
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
391
 
 
392
        tree.commit("added")
 
393
        result = self.run_bzr("status --versioned -r 0..1")[0]
 
394
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
395
 
 
396
        self.build_tree(['world.txt'])
 
397
        result = self.run_bzr("status --versioned -r 0")[0]
 
398
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
399
        self.assertNotContainsRe(result, "unknown:\n  world.txt\n")
 
400
        result2 = self.run_bzr("status --versioned -r 0..")[0]
 
401
        self.assertEquals(result2, result)
 
402
 
 
403
    def test_status_SV(self):
 
404
        tree = self.make_branch_and_tree('.')
 
405
 
 
406
        self.build_tree(['hello.txt'])
 
407
        result = self.run_bzr("status -SV")[0]
 
408
        self.assertNotContainsRe(result, "hello.txt")
 
409
 
 
410
        tree.add("hello.txt")
 
411
        result = self.run_bzr("status -SV")[0]
 
412
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
413
 
 
414
        tree.commit(message="added")
 
415
        result = self.run_bzr("status -SV -r 0..1")[0]
 
416
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
417
 
 
418
        self.build_tree(['world.txt'])
 
419
        result = self.run_bzr("status -SV -r 0")[0]
 
420
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
421
 
 
422
        result2 = self.run_bzr("status -SV -r 0..")[0]
 
423
        self.assertEquals(result2, result)
 
424
 
 
425
    def assertStatusContains(self, pattern):
 
426
        """Run status, and assert it contains the given pattern"""
 
427
        result = self.run_bzr("status --short")[0]
 
428
        self.assertContainsRe(result, pattern)
 
429
 
 
430
    def test_kind_change_short(self):
 
431
        tree = self.make_branch_and_tree('.')
 
432
        self.build_tree(['file'])
 
433
        tree.add('file')
 
434
        tree.commit('added file')
 
435
        unlink('file')
 
436
        self.build_tree(['file/'])
 
437
        self.assertStatusContains('K  file => file/')
 
438
        tree.rename_one('file', 'directory')
 
439
        self.assertStatusContains('RK  file => directory/')
 
440
        rmdir('directory')
 
441
        self.assertStatusContains('RD  file => directory')
 
442
 
 
443
    def test_status_illegal_revision_specifiers(self):
 
444
        out, err = self.run_bzr('status -r 1..23..123', retcode=3)
 
445
        self.assertContainsRe(err, 'one or two revision specifiers')
 
446
 
 
447
    def test_status_no_pending(self):
 
448
        a_tree = self.make_branch_and_tree('a')
 
449
        self.build_tree(['a/a'])
 
450
        a_tree.add('a')
 
451
        a_tree.commit('a')
 
452
        b_tree = a_tree.bzrdir.sprout('b').open_workingtree()
 
453
        self.build_tree(['b/b'])
 
454
        b_tree.add('b')
 
455
        b_tree.commit('b')
 
456
 
 
457
        self.run_bzr('merge ../b', working_dir='a')
 
458
        out, err = self.run_bzr('status --no-pending', working_dir='a')
 
459
        self.assertEquals(out, "added:\n  b\n")
 
460
 
 
461
    def test_pending_specific_files(self):
 
462
        """With a specific file list, pending merges are not shown."""
 
463
        tree = self.make_branch_and_tree('tree')
 
464
        self.build_tree_contents([('tree/a', 'content of a\n')])
 
465
        tree.add('a')
 
466
        r1_id = tree.commit('one')
 
467
        alt = tree.bzrdir.sprout('alt').open_workingtree()
 
468
        self.build_tree_contents([('alt/a', 'content of a\nfrom alt\n')])
 
469
        alt_id = alt.commit('alt')
 
470
        tree.merge_from_branch(alt.branch)
 
471
        output = self.make_utf8_encoded_stringio()
 
472
        show_tree_status(tree, to_file=output)
 
473
        self.assertContainsRe(output.getvalue(), 'pending merges:')
 
474
        out, err = self.run_bzr('status tree/a')
 
475
        self.assertNotContainsRe(out, 'pending merges:')
 
476
 
 
477
 
 
478
class TestStatusEncodings(TestCaseWithTransport):
 
479
    
 
480
    def setUp(self):
 
481
        TestCaseWithTransport.setUp(self)
 
482
        self.user_encoding = osutils._cached_user_encoding
 
483
        self.stdout = sys.stdout
 
484
 
 
485
    def tearDown(self):
 
486
        bzrlib.user_encoding = self.user_encoding
 
487
        sys.stdout = self.stdout
 
488
        TestCaseWithTransport.tearDown(self)
 
489
 
 
490
    def make_uncommitted_tree(self):
 
491
        """Build a branch with uncommitted unicode named changes in the cwd."""
 
492
        working_tree = self.make_branch_and_tree(u'.')
 
493
        filename = u'hell\u00d8'
 
494
        try:
 
495
            self.build_tree_contents([(filename, 'contents of hello')])
 
496
        except UnicodeEncodeError:
 
497
            raise TestSkipped("can't build unicode working tree in "
 
498
                "filesystem encoding %s" % sys.getfilesystemencoding())
 
499
        working_tree.add(filename)
 
500
        return working_tree
 
501
 
 
502
    def test_stdout_ascii(self):
 
503
        sys.stdout = StringIO()
 
504
        osutils._cached_user_encoding = 'ascii'
 
505
        working_tree = self.make_uncommitted_tree()
 
506
        stdout, stderr = self.run_bzr("status")
 
507
 
 
508
        self.assertEquals(stdout, """\
 
509
added:
 
510
  hell?
 
511
""")
 
512
 
 
513
    def test_stdout_latin1(self):
 
514
        sys.stdout = StringIO()
 
515
        osutils._cached_user_encoding = 'latin-1'
 
516
        working_tree = self.make_uncommitted_tree()
 
517
        stdout, stderr = self.run_bzr('status')
 
518
 
 
519
        self.assertEquals(stdout, u"""\
 
520
added:
 
521
  hell\u00d8
 
522
""".encode('latin-1'))
 
523