~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Ian Clatworthy
  • Date: 2007-06-06 11:51:37 UTC
  • mto: This revision was merged to the branch mainline in revision 2527.
  • Revision ID: ian.clatworthy@internode.on.net-20070606115137-iq6sk13d8p356bo8
explicit format saving test

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
2
 
 
 
1
# Copyright (C) 2005, 2006 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
 
 
18
17
"""Tests of status command.
19
18
 
20
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.
21
23
"""
22
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
23
30
 
24
 
from bzrlib.selftest import TestCaseInTempDir
 
31
from bzrlib import bzrdir, errors
 
32
import bzrlib.branch
 
33
from bzrlib.builtins import merge
 
34
from bzrlib.osutils import pathjoin
25
35
from bzrlib.revisionspec import RevisionSpec
26
 
from bzrlib.merge import merge
27
 
from cStringIO import StringIO
28
 
from bzrlib.status import show_status
29
 
from bzrlib.branch import Branch
30
 
from os import mkdir
31
 
from bzrlib.clone import copy_branch
32
 
 
33
 
class BranchStatus(TestCaseInTempDir):
34
 
    
35
 
    def test_branch_status(self): 
 
36
from bzrlib.status import show_tree_status
 
37
from bzrlib.tests import TestCaseWithTransport, TestSkipped
 
38
from bzrlib.workingtree import WorkingTree
 
39
 
 
40
 
 
41
class BranchStatus(TestCaseWithTransport):
 
42
    
 
43
    def assertStatus(self, expected_lines, working_tree,
 
44
        revision=None, short=False):
 
45
        """Run status in working_tree and look for output.
 
46
        
 
47
        :param expected_lines: The lines to look for.
 
48
        :param working_tree: The tree to run status in.
 
49
        """
 
50
        output_string = self.status_string(working_tree, revision, short)
 
51
        self.assertEqual(expected_lines, output_string.splitlines(True))
 
52
    
 
53
    def status_string(self, wt, revision=None, short=False):
 
54
        # use a real file rather than StringIO because it doesn't handle
 
55
        # Unicode very well.
 
56
        tof = codecs.getwriter('utf-8')(TemporaryFile())
 
57
        show_tree_status(wt, to_file=tof, revision=revision, short=short)
 
58
        tof.seek(0)
 
59
        return tof.read().decode('utf-8')
 
60
 
 
61
    def test_branch_status(self):
36
62
        """Test basic branch status"""
37
 
        from cStringIO import StringIO
38
 
        from bzrlib.status import show_status
39
 
        from bzrlib.branch import Branch
40
 
        
41
 
        b = Branch.initialize('.')
42
 
 
43
 
        # status with nothing
44
 
        tof = StringIO()
45
 
        show_status(b, to_file=tof)
46
 
        self.assertEquals(tof.getvalue(), "")
47
 
 
48
 
        tof = StringIO()
 
63
        wt = self.make_branch_and_tree('.')
 
64
 
 
65
        # status with no commits or files - it must
 
66
        # work and show no output. We do this with no
 
67
        # commits to be sure that it's not going to fail
 
68
        # as a corner case.
 
69
        self.assertStatus([], wt)
 
70
 
49
71
        self.build_tree(['hello.c', 'bye.c'])
50
 
        b.working_tree().add_pending_merge('pending@pending-0-0')
51
 
        show_status(b, to_file=tof)
52
 
        tof.seek(0)
53
 
        self.assertEquals(tof.readlines(),
54
 
                          ['unknown:\n',
55
 
                           '  bye.c\n',
56
 
                           '  hello.c\n',
57
 
                           'pending merges:\n',
58
 
                           '  pending@pending-0-0\n'
59
 
                           ])
 
72
        self.assertStatus([
 
73
                'unknown:\n',
 
74
                '  bye.c\n',
 
75
                '  hello.c\n',
 
76
            ],
 
77
            wt)
 
78
        self.assertStatus([
 
79
                '?   bye.c\n',
 
80
                '?   hello.c\n',
 
81
            ],
 
82
            wt, short=True)
 
83
 
 
84
        # add a commit to allow showing pending merges.
 
85
        wt.commit('create a parent to allow testing merge output')
 
86
 
 
87
        wt.add_parent_tree_id('pending@pending-0-0')
 
88
        self.assertStatus([
 
89
                'unknown:\n',
 
90
                '  bye.c\n',
 
91
                '  hello.c\n',
 
92
                'pending merges:\n',
 
93
                '  pending@pending-0-0\n',
 
94
            ],
 
95
            wt)
 
96
        self.assertStatus([
 
97
                '?   bye.c\n',
 
98
                '?   hello.c\n',
 
99
                'P   pending@pending-0-0\n',
 
100
            ],
 
101
            wt, short=True)
60
102
 
61
103
    def test_branch_status_revisions(self):
62
104
        """Tests branch status with revisions"""
63
 
        
64
 
        b = Branch.initialize('.')
 
105
        wt = self.make_branch_and_tree('.')
65
106
 
66
 
        tof = StringIO()
67
107
        self.build_tree(['hello.c', 'bye.c'])
68
 
        b.add('hello.c')
69
 
        b.add('bye.c')
70
 
        b.working_tree().commit('Test message')
 
108
        wt.add('hello.c')
 
109
        wt.add('bye.c')
 
110
        wt.commit('Test message')
71
111
 
72
 
        tof = StringIO()
73
 
        revs =[]
74
 
        revs.append(RevisionSpec(0))
75
 
        
76
 
        show_status(b, to_file=tof, revision=revs)
77
 
        
78
 
        tof.seek(0)
79
 
        self.assertEquals(tof.readlines(),
80
 
                          ['added:\n',
81
 
                           '  bye.c\n',
82
 
                           '  hello.c\n'])
 
112
        revs = [RevisionSpec.from_string('0')]
 
113
        self.assertStatus([
 
114
                'added:\n',
 
115
                '  bye.c\n',
 
116
                '  hello.c\n'
 
117
            ],
 
118
            wt,
 
119
            revision=revs)
83
120
 
84
121
        self.build_tree(['more.c'])
85
 
        b.add('more.c')
86
 
        b.working_tree().commit('Another test message')
87
 
        
88
 
        tof = StringIO()
89
 
        revs.append(RevisionSpec(1))
90
 
        
91
 
        show_status(b, to_file=tof, revision=revs)
92
 
        
93
 
        tof.seek(0)
94
 
        self.assertEquals(tof.readlines(),
95
 
                          ['added:\n',
96
 
                           '  bye.c\n',
97
 
                           '  hello.c\n'])
98
 
 
99
 
    def status_string(self, branch):
100
 
        tof = StringIO()
101
 
        show_status(branch, to_file=tof)
102
 
        tof.seek(0)
103
 
        return tof.getvalue()
 
122
        wt.add('more.c')
 
123
        wt.commit('Another test message')
 
124
        
 
125
        revs.append(RevisionSpec.from_string('1'))
 
126
        self.assertStatus([
 
127
                'added:\n',
 
128
                '  bye.c\n',
 
129
                '  hello.c\n',
 
130
            ],
 
131
            wt,
 
132
            revision=revs)
104
133
 
105
134
    def test_pending(self):
106
 
        """Pending merges display works"""
 
135
        """Pending merges display works, including Unicode"""
107
136
        mkdir("./branch")
108
 
        b = Branch.initialize('./branch')
109
 
        b.working_tree().commit("Empty commit 1")
110
 
        b_2 = copy_branch(b, './copy')
111
 
        b.working_tree().commit("Empty commit 2")
 
137
        wt = self.make_branch_and_tree('branch')
 
138
        b = wt.branch
 
139
        wt.commit("Empty commit 1")
 
140
        b_2_dir = b.bzrdir.sprout('./copy')
 
141
        b_2 = b_2_dir.open_branch()
 
142
        wt2 = b_2_dir.open_workingtree()
 
143
        wt.commit(u"\N{TIBETAN DIGIT TWO} Empty commit 2")
112
144
        merge(["./branch", -1], [None, None], this_dir = './copy')
113
 
        message = self.status_string(b_2)
114
 
        self.assert_(message.startswith("pending merges:\n"))
115
 
        self.assert_(message.endswith("Empty commit 2\n")) 
116
 
        b_2.working_tree().commit("merged")
 
145
        message = self.status_string(wt2)
 
146
        self.assertStartsWith(message, "pending merges:\n")
 
147
        self.assertEndsWith(message, "Empty commit 2\n")
 
148
        wt2.commit("merged")
117
149
        # must be long to make sure we see elipsis at the end
118
 
        b.working_tree().commit("Empty commit 3 blah blah blah blah blah blah blah blah blah"
119
 
                 " blah blah blah blah blah blah bleh")
 
150
        wt.commit("Empty commit 3 " +
 
151
                   "blah blah blah blah " * 100)
120
152
        merge(["./branch", -1], [None, None], this_dir = './copy')
121
 
        message = self.status_string(b_2)
122
 
        self.assert_(message.startswith("pending merges:\n"))
 
153
        message = self.status_string(wt2)
 
154
        self.assertStartsWith(message, "pending merges:\n")
123
155
        self.assert_("Empty commit 3" in message)
124
 
        self.assert_(message.endswith("...\n")) 
125
 
 
126
 
    def test_branch_status_specific_files(self): 
 
156
        self.assertEndsWith(message, "...\n")
 
157
 
 
158
    def test_tree_status_ignores(self):
 
159
        """Tests branch status with ignores"""
 
160
        wt = self.make_branch_and_tree('.')
 
161
        self.run_bzr('ignore', '*~')
 
162
        wt.commit('commit .bzrignore')
 
163
        self.build_tree(['foo.c', 'foo.c~'])
 
164
        self.assertStatus([
 
165
                'unknown:\n',
 
166
                '  foo.c\n',
 
167
                ],
 
168
                wt)
 
169
        self.assertStatus([
 
170
                '?   foo.c\n',
 
171
                ],
 
172
                wt, short=True)
 
173
 
 
174
    def test_tree_status_specific_files(self):
127
175
        """Tests branch status with given specific files"""
128
 
        from cStringIO import StringIO
129
 
        from bzrlib.status import show_status
130
 
        from bzrlib.branch import Branch
131
 
        
132
 
        b = Branch.initialize('.')
 
176
        wt = self.make_branch_and_tree('.')
 
177
        b = wt.branch
133
178
 
134
179
        self.build_tree(['directory/','directory/hello.c', 'bye.c','test.c','dir2/'])
135
 
        b.add('directory')
136
 
        b.add('test.c')
137
 
        b.working_tree().commit('testing')
138
 
        
139
 
        tof = StringIO()
140
 
        show_status(b, to_file=tof)
141
 
        tof.seek(0)
142
 
        self.assertEquals(tof.readlines(),
143
 
                          ['unknown:\n',
144
 
                           '  bye.c\n',
145
 
                           '  dir2\n',
146
 
                           '  directory/hello.c\n'
147
 
                           ])
148
 
 
149
 
        tof = StringIO()
150
 
        show_status(b, specific_files=['bye.c','test.c','absent.c'], to_file=tof)
151
 
        tof.seek(0)
152
 
        self.assertEquals(tof.readlines(),
153
 
                          ['unknown:\n',
154
 
                           '  bye.c\n'
155
 
                           ])
156
 
        
157
 
        tof = StringIO()
158
 
        show_status(b, specific_files=['directory'], to_file=tof)
159
 
        tof.seek(0)
160
 
        self.assertEquals(tof.readlines(),
161
 
                          ['unknown:\n',
162
 
                           '  directory/hello.c\n'
163
 
                           ])
164
 
        tof = StringIO()
165
 
        show_status(b, specific_files=['dir2'], to_file=tof)
166
 
        tof.seek(0)
167
 
        self.assertEquals(tof.readlines(),
168
 
                          ['unknown:\n',
169
 
                           '  dir2\n'
170
 
                           ])
 
180
        wt.add('directory')
 
181
        wt.add('test.c')
 
182
        wt.commit('testing')
 
183
        
 
184
        self.assertStatus([
 
185
                'unknown:\n',
 
186
                '  bye.c\n',
 
187
                '  dir2/\n',
 
188
                '  directory/hello.c\n'
 
189
                ],
 
190
                wt)
 
191
 
 
192
        self.assertStatus([
 
193
                '?   bye.c\n',
 
194
                '?   dir2/\n',
 
195
                '?   directory/hello.c\n'
 
196
                ],
 
197
                wt, short=True)
 
198
 
 
199
        tof = StringIO()
 
200
        self.assertRaises(errors.PathsDoNotExist,
 
201
                          show_tree_status,
 
202
                          wt, specific_files=['bye.c','test.c','absent.c'], 
 
203
                          to_file=tof)
 
204
        
 
205
        tof = StringIO()
 
206
        show_tree_status(wt, specific_files=['directory'], to_file=tof)
 
207
        tof.seek(0)
 
208
        self.assertEquals(tof.readlines(),
 
209
                          ['unknown:\n',
 
210
                           '  directory/hello.c\n'
 
211
                           ])
 
212
        tof = StringIO()
 
213
        show_tree_status(wt, specific_files=['directory'], to_file=tof,
 
214
                         short=True)
 
215
        tof.seek(0)
 
216
        self.assertEquals(tof.readlines(), ['?   directory/hello.c\n'])
 
217
 
 
218
        tof = StringIO()
 
219
        show_tree_status(wt, specific_files=['dir2'], to_file=tof)
 
220
        tof.seek(0)
 
221
        self.assertEquals(tof.readlines(),
 
222
                          ['unknown:\n',
 
223
                           '  dir2/\n'
 
224
                           ])
 
225
        tof = StringIO()
 
226
        show_tree_status(wt, specific_files=['dir2'], to_file=tof, short=True)
 
227
        tof.seek(0)
 
228
        self.assertEquals(tof.readlines(), ['?   dir2/\n'])
 
229
 
 
230
    def test_status_nonexistent_file(self):
 
231
        # files that don't exist in either the basis tree or working tree
 
232
        # should give an error
 
233
        wt = self.make_branch_and_tree('.')
 
234
        out, err = self.run_bzr('status', 'does-not-exist', retcode=3)
 
235
        self.assertContainsRe(err, r'do not exist.*does-not-exist')
 
236
 
 
237
    def test_status_out_of_date(self):
 
238
        """Simulate status of out-of-date tree after remote push"""
 
239
        tree = self.make_branch_and_tree('.')
 
240
        self.build_tree_contents([('a', 'foo\n')])
 
241
        tree.lock_write()
 
242
        try:
 
243
            tree.add(['a'])
 
244
            tree.commit('add test file')
 
245
            # simulate what happens after a remote push
 
246
            tree.set_last_revision("0")
 
247
        finally:
 
248
            # before run another commands we should unlock tree
 
249
            tree.unlock()
 
250
        out, err = self.run_bzr('status')
 
251
        self.assertEqual("working tree is out of date, run 'bzr update'\n",
 
252
                         err)
 
253
 
 
254
 
 
255
class CheckoutStatus(BranchStatus):
 
256
 
 
257
    def setUp(self):
 
258
        super(CheckoutStatus, self).setUp()
 
259
        mkdir('codir')
 
260
        chdir('codir')
 
261
        
 
262
    def make_branch_and_tree(self, relpath):
 
263
        source = self.make_branch(pathjoin('..', relpath))
 
264
        checkout = bzrdir.BzrDirMetaFormat1().initialize(relpath)
 
265
        bzrlib.branch.BranchReferenceFormat().initialize(checkout, source)
 
266
        return checkout.create_workingtree()
 
267
 
 
268
 
 
269
class TestStatus(TestCaseWithTransport):
 
270
 
 
271
    def test_status_plain(self):
 
272
        self.run_bzr("init")
 
273
 
 
274
        self.build_tree(['hello.txt'])
 
275
        result = self.run_bzr("status")[0]
 
276
        self.assertContainsRe(result, "unknown:\n  hello.txt\n")
 
277
 
 
278
        self.run_bzr("add", "hello.txt")
 
279
        result = self.run_bzr("status")[0]
 
280
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
281
 
 
282
        self.run_bzr("commit", "-m", "added")
 
283
        result = self.run_bzr("status", "-r", "0..1")[0]
 
284
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
285
 
 
286
        self.build_tree(['world.txt'])
 
287
        result = self.run_bzr("status", "-r", "0")[0]
 
288
        self.assertContainsRe(result, "added:\n  hello.txt\n" \
 
289
                                      "unknown:\n  world.txt\n")
 
290
        result2 = self.run_bzr("status", "-r", "0..")[0]
 
291
        self.assertEquals(result2, result)
 
292
 
 
293
    def test_status_short(self):
 
294
        self.run_bzr("init")
 
295
 
 
296
        self.build_tree(['hello.txt'])
 
297
        result = self.run_bzr("status","--short")[0]
 
298
        self.assertContainsRe(result, "[?]   hello.txt\n")
 
299
 
 
300
        self.run_bzr("add", "hello.txt")
 
301
        result = self.run_bzr("status","--short")[0]
 
302
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
303
 
 
304
        self.run_bzr("commit", "-m", "added")
 
305
        result = self.run_bzr("status", "--short", "-r", "0..1")[0]
 
306
        self.assertContainsRe(result, "[+]N  hello.txt\n")
 
307
 
 
308
        self.build_tree(['world.txt'])
 
309
        result = self.run_bzr("status", "--short", "-r", "0")[0]
 
310
        self.assertContainsRe(result, "[+]N  hello.txt\n" \
 
311
                                      "[?]   world.txt\n")
 
312
        result2 = self.run_bzr("status", "--short", "-r", "0..")[0]
 
313
        self.assertEquals(result2, result)
 
314
 
 
315
    def test_status_versioned(self):
 
316
        self.run_bzr("init")
 
317
 
 
318
        self.build_tree(['hello.txt'])
 
319
        result = self.run_bzr("status", "--versioned")[0]
 
320
        self.assertNotContainsRe(result, "unknown:\n  hello.txt\n")
 
321
 
 
322
        self.run_bzr("add", "hello.txt")
 
323
        result = self.run_bzr("status", "--versioned")[0]
 
324
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
325
 
 
326
        self.run_bzr("commit", "-m", "added")
 
327
        result = self.run_bzr("status", "--versioned", "-r", "0..1")[0]
 
328
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
329
 
 
330
        self.build_tree(['world.txt'])
 
331
        result = self.run_bzr("status", "--versioned", "-r", "0")[0]
 
332
        self.assertContainsRe(result, "added:\n  hello.txt\n")
 
333
        self.assertNotContainsRe(result, "unknown:\n  world.txt\n")
 
334
        result2 = self.run_bzr("status", "--versioned", "-r", "0..")[0]
 
335
        self.assertEquals(result2, result)
 
336
 
 
337
    def assertStatusContains(self, pattern):
 
338
        """Run status, and assert it contains the given pattern"""
 
339
        result = self.run_bzr("status", "--short")[0]
 
340
        self.assertContainsRe(result, pattern)
 
341
 
 
342
    def test_kind_change_short(self):
 
343
        tree = self.make_branch_and_tree('.')
 
344
        self.build_tree(['file'])
 
345
        tree.add('file')
 
346
        tree.commit('added file')
 
347
        unlink('file')
 
348
        self.build_tree(['file/'])
 
349
        self.assertStatusContains('K  file => file/')
 
350
        tree.rename_one('file', 'directory')
 
351
        self.assertStatusContains('RK  file => directory/')
 
352
        rmdir('directory')
 
353
        self.assertStatusContains('RD  file => directory')
 
354
 
 
355
 
 
356
class TestStatusEncodings(TestCaseWithTransport):
 
357
    
 
358
    def setUp(self):
 
359
        TestCaseWithTransport.setUp(self)
 
360
        self.user_encoding = bzrlib.user_encoding
 
361
        self.stdout = sys.stdout
 
362
 
 
363
    def tearDown(self):
 
364
        bzrlib.user_encoding = self.user_encoding
 
365
        sys.stdout = self.stdout
 
366
        TestCaseWithTransport.tearDown(self)
 
367
 
 
368
    def make_uncommitted_tree(self):
 
369
        """Build a branch with uncommitted unicode named changes in the cwd."""
 
370
        working_tree = self.make_branch_and_tree(u'.')
 
371
        filename = u'hell\u00d8'
 
372
        try:
 
373
            self.build_tree_contents([(filename, 'contents of hello')])
 
374
        except UnicodeEncodeError:
 
375
            raise TestSkipped("can't build unicode working tree in "
 
376
                "filesystem encoding %s" % sys.getfilesystemencoding())
 
377
        working_tree.add(filename)
 
378
        return working_tree
 
379
 
 
380
    def test_stdout_ascii(self):
 
381
        sys.stdout = StringIO()
 
382
        bzrlib.user_encoding = 'ascii'
 
383
        working_tree = self.make_uncommitted_tree()
 
384
        stdout, stderr = self.run_bzr("status")
 
385
 
 
386
        self.assertEquals(stdout, """\
 
387
added:
 
388
  hell?
 
389
""")
 
390
 
 
391
    def test_stdout_latin1(self):
 
392
        sys.stdout = StringIO()
 
393
        bzrlib.user_encoding = 'latin-1'
 
394
        working_tree = self.make_uncommitted_tree()
 
395
        stdout, stderr = self.run_bzr('status')
 
396
 
 
397
        self.assertEquals(stdout, u"""\
 
398
added:
 
399
  hell\u00d8
 
400
""".encode('latin-1'))
 
401