~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/teststatus.py

  • Committer: Martin Pool
  • Date: 2005-08-04 22:30:50 UTC
  • Revision ID: mbp@sourcefrog.net-20050804223050-01256e5e26a90b1d
- merge patch to take ranges to diff -r option

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 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
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
 
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'))
 
23
 
 
24
from bzrlib.selftest import InTempDir
 
25
 
 
26
class BranchStatus(InTempDir):
 
27
    def runTest(self): 
 
28
        """Basic 'bzr mkdir' operation"""
 
29
        from cStringIO import StringIO
 
30
        from bzrlib.status import show_status
 
31
        from bzrlib.branch import Branch
 
32
        
 
33
        b = Branch('.', init=True)
 
34
 
 
35
        # status with nothing
 
36
        tof = StringIO()
 
37
        show_status(b, to_file=tof)
 
38
        self.assertEquals(tof.getvalue(), "")
 
39
 
 
40
        tof = StringIO()
 
41
        self.build_tree(['hello.c', 'bye.c'])
 
42
        show_status(b, to_file=tof)
 
43
        tof.seek(0)
 
44
        self.assertEquals(tof.readlines(),
 
45
                          ['unknown:\n',
 
46
                           '  bye.c\n',
 
47
                           '  hello.c\n',
 
48
                           ])
523
49