/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_log.py

  • Committer: Robert Collins
  • Date: 2007-04-26 01:48:29 UTC
  • mto: This revision was merged to the branch mainline in revision 2457.
  • Revision ID: robertc@robertcollins.net-20070426014829-znbzqzsk1gq68xqh
Fix the 'Unprintable error' message display to use the repr of the
exception that prevented printing the error because the str value for it
is often not useful in debugging (e.g.  KeyError('foo') has a str() of
'foo' but a repr of 'KeyError('foo')' which is much more useful.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
2
# -*- coding: utf-8 -*-
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
 
18
 
 
19
"""Black-box tests for bzr log."""
 
20
 
 
21
import os
 
22
 
 
23
import bzrlib
 
24
from bzrlib.tests.blackbox import ExternalBase
 
25
from bzrlib.tests import TestCaseInTempDir, TestCaseWithTransport
 
26
 
 
27
 
 
28
class TestLog(ExternalBase):
 
29
 
 
30
    def _prepare(self, format=None):
 
31
        if format:
 
32
            self.runbzr("init --format="+format)
 
33
        else:
 
34
            self.runbzr("init")
 
35
        self.build_tree(['hello.txt', 'goodbye.txt', 'meep.txt'])
 
36
        self.runbzr("add hello.txt")
 
37
        self.runbzr("commit -m message1 hello.txt")
 
38
        self.runbzr("add goodbye.txt")
 
39
        self.runbzr("commit -m message2 goodbye.txt")
 
40
        self.runbzr("add meep.txt")
 
41
        self.runbzr("commit -m message3 meep.txt")
 
42
        self.full_log = self.runbzr("log")[0]
 
43
 
 
44
    def test_log_null_end_revspec(self):
 
45
        self._prepare()
 
46
        self.assertTrue('revno: 1\n' in self.full_log)
 
47
        self.assertTrue('revno: 2\n' in self.full_log)
 
48
        self.assertTrue('revno: 3\n' in self.full_log)
 
49
        self.assertTrue('message:\n  message1\n' in self.full_log)
 
50
        self.assertTrue('message:\n  message2\n' in self.full_log)
 
51
        self.assertTrue('message:\n  message3\n' in self.full_log)
 
52
 
 
53
        log = self.runbzr("log -r 1..")[0]
 
54
        self.assertEquals(log, self.full_log)
 
55
 
 
56
    def test_log_null_begin_revspec(self):
 
57
        self._prepare()
 
58
        log = self.runbzr("log -r ..3")[0]
 
59
        self.assertEquals(self.full_log, log)
 
60
 
 
61
    def test_log_null_both_revspecs(self):
 
62
        self._prepare()
 
63
        log = self.runbzr("log -r ..")[0]
 
64
        self.assertEquals(self.full_log, log)
 
65
 
 
66
    def test_log_negative_begin_revspec_full_log(self):
 
67
        self._prepare()
 
68
        log = self.runbzr("log -r -3..")[0]
 
69
        self.assertEquals(self.full_log, log)
 
70
 
 
71
    def test_log_negative_both_revspec_full_log(self):
 
72
        self._prepare()
 
73
        log = self.runbzr("log -r -3..-1")[0]
 
74
        self.assertEquals(self.full_log, log)
 
75
 
 
76
    def test_log_negative_both_revspec_partial(self):
 
77
        self._prepare()
 
78
        log = self.runbzr("log -r -3..-2")[0]
 
79
        self.assertTrue('revno: 1\n' in log)
 
80
        self.assertTrue('revno: 2\n' in log)
 
81
        self.assertTrue('revno: 3\n' not in log)
 
82
 
 
83
    def test_log_negative_begin_revspec(self):
 
84
        self._prepare()
 
85
        log = self.runbzr("log -r -2..")[0]
 
86
        self.assertTrue('revno: 1\n' not in log)
 
87
        self.assertTrue('revno: 2\n' in log)
 
88
        self.assertTrue('revno: 3\n' in log)
 
89
 
 
90
    def test_log_postive_revspecs(self):
 
91
        self._prepare()
 
92
        log = self.runbzr("log -r 1..3")[0]
 
93
        self.assertEquals(self.full_log, log)
 
94
 
 
95
    def test_log_revno_n_path(self):
 
96
        os.mkdir('branch1')
 
97
        os.chdir('branch1')
 
98
        self._prepare()
 
99
        os.chdir('..')
 
100
        os.mkdir('branch2')
 
101
        os.chdir('branch2')
 
102
        self._prepare()
 
103
        os.chdir('..')
 
104
        log = self.runbzr("log -r revno:2:branch1..revno:3:branch2",
 
105
                          retcode=3)[0]
 
106
        log = self.runbzr("log -r revno:1:branch2..revno:3:branch2")[0]
 
107
        self.assertEquals(self.full_log, log)
 
108
        log = self.runbzr("log -r revno:1:branch2")[0]
 
109
        self.assertTrue('revno: 1\n' in log)
 
110
        self.assertTrue('revno: 2\n' not in log)
 
111
        self.assertTrue('branch nick: branch2\n' in log)
 
112
        self.assertTrue('branch nick: branch1\n' not in log)
 
113
        
 
114
    def test_log_nonexistent_file(self):
 
115
        # files that don't exist in either the basis tree or working tree
 
116
        # should give an error
 
117
        wt = self.make_branch_and_tree('.')
 
118
        out, err = self.run_bzr('log', 'does-not-exist', retcode=3)
 
119
        self.assertContainsRe(
 
120
            err, 'Path does not have any revision history: does-not-exist')
 
121
 
 
122
    def test_log_with_tags(self):
 
123
        self._prepare(format='dirstate-tags')
 
124
        self.runbzr('tag -r1 tag1')
 
125
        self.runbzr('tag -r1 tag1.1')
 
126
        self.runbzr('tag tag3')
 
127
        
 
128
        log = self.runbzr("log -r-1")[0]
 
129
        self.assertTrue('tags: tag3' in log)
 
130
 
 
131
        log = self.runbzr("log -r1")[0]
 
132
        # I guess that we can't know the order of tags in the output
 
133
        # since dicts are unordered, need to check both possibilities
 
134
        self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)')
 
135
 
 
136
    def test_merged_log_with_tags(self):
 
137
        os.mkdir('branch1')
 
138
        os.chdir('branch1')
 
139
        self._prepare(format='dirstate-tags')
 
140
        os.chdir('..')
 
141
        self.runbzr('branch branch1 branch2')
 
142
        os.chdir('branch1')
 
143
        self.runbzr('commit -m foobar --unchanged')
 
144
        self.runbzr('tag tag1')
 
145
        os.chdir('../branch2')
 
146
        self.runbzr('merge ../branch1')
 
147
        self.runbzr('commit -m merge_branch_1')
 
148
        log = self.runbzr("log -r-1")[0]
 
149
        self.assertContainsRe(log, r'    tags: tag1')
 
150
 
 
151
 
 
152
class TestLogMerges(ExternalBase):
 
153
 
 
154
    def test_merges_are_indented_by_level(self):
 
155
        self.build_tree(['parent/'])
 
156
        self.run_bzr('init', 'parent')
 
157
        self.run_bzr('commit', '-m', 'first post', '--unchanged', 'parent')
 
158
        self.run_bzr('branch', 'parent', 'child')
 
159
        self.run_bzr('commit', '-m', 'branch 1', '--unchanged', 'child')
 
160
        self.run_bzr('branch', 'child', 'smallerchild')
 
161
        self.run_bzr('commit', '-m', 'branch 2', '--unchanged', 'smallerchild')
 
162
        os.chdir('child')
 
163
        self.run_bzr('merge', '../smallerchild')
 
164
        self.run_bzr('commit', '-m', 'merge branch 2')
 
165
        os.chdir('../parent')
 
166
        self.run_bzr('merge', '../child')
 
167
        self.run_bzr('commit', '-m', 'merge branch 1')
 
168
        out,err = self.run_bzr('log')
 
169
        # the log will look something like:
 
170
#        self.assertEqual("""\
 
171
#------------------------------------------------------------
 
172
#revno: 2
 
173
#committer: Robert Collins <foo@example.com>
 
174
#branch nick: parent
 
175
#timestamp: Tue 2006-03-28 22:31:40 +1100
 
176
#message:
 
177
#  merge branch 1
 
178
#    ------------------------------------------------------------
 
179
#    revno: 1.1.2  
 
180
#    merged: foo@example.com-20060328113140-91f43cfb46dc2863
 
181
#    committer: Robert Collins <foo@example.com>
 
182
#    branch nick: child
 
183
#    timestamp: Tue 2006-03-28 22:31:40 +1100
 
184
#    message:
 
185
#      merge branch 2
 
186
#        ------------------------------------------------------------
 
187
#        revno: 1.1.1.1
 
188
#        merged: foo@example.com-20060328113140-1ba24f850a0ef573
 
189
#        committer: Robert Collins <foo@example.com>
 
190
#        branch nick: smallerchild
 
191
#        timestamp: Tue 2006-03-28 22:31:40 +1100
 
192
#        message:
 
193
#          branch 2
 
194
#    ------------------------------------------------------------
 
195
#    revno: 1.1.1
 
196
#    merged: foo@example.com-20060328113140-5749a4757a8ac792
 
197
#    committer: Robert Collins <foo@example.com>
 
198
#    branch nick: child
 
199
#    timestamp: Tue 2006-03-28 22:31:40 +1100
 
200
#    message:
 
201
#      branch 1
 
202
#------------------------------------------------------------
 
203
#revno: 1
 
204
#committer: Robert Collins <foo@example.com>
 
205
#branch nick: parent
 
206
#timestamp: Tue 2006-03-28 22:31:39 +1100
 
207
#message:
 
208
#  first post
 
209
#""", out)
 
210
        # but we dont have a nice pattern matcher hooked up yet, so:
 
211
        # we check for the indenting of the commit message and the 
 
212
        # revision numbers 
 
213
        self.assertTrue('revno: 2' in out)
 
214
        self.assertTrue('  merge branch 1' in out)
 
215
        self.assertTrue('    revno: 1.1.2' in out)
 
216
        self.assertTrue('      merge branch 2' in out)
 
217
        self.assertTrue('        revno: 1.1.1.1' in out)
 
218
        self.assertTrue('          branch 2' in out)
 
219
        self.assertTrue('    revno: 1.1.1' in out)
 
220
        self.assertTrue('      branch 1' in out)
 
221
        self.assertTrue('revno: 1' in out)
 
222
        self.assertTrue('  first post' in out)
 
223
        self.assertEqual('', err)
 
224
 
 
225
 
 
226
class TestLogEncodings(TestCaseInTempDir):
 
227
 
 
228
    _mu = u'\xb5'
 
229
    _message = u'Message with \xb5'
 
230
 
 
231
    # Encodings which can encode mu
 
232
    good_encodings = [
 
233
        'utf-8',
 
234
        'latin-1',
 
235
        'iso-8859-1',
 
236
        'cp437', # Common windows encoding
 
237
        'cp1251', # Alexander Belchenko's windows encoding
 
238
        'cp1258', # Common windows encoding
 
239
    ]
 
240
    # Encodings which cannot encode mu
 
241
    bad_encodings = [
 
242
        'ascii',
 
243
        'iso-8859-2',
 
244
        'koi8_r',
 
245
    ]
 
246
 
 
247
    def setUp(self):
 
248
        TestCaseInTempDir.setUp(self)
 
249
        self.user_encoding = bzrlib.user_encoding
 
250
 
 
251
    def tearDown(self):
 
252
        bzrlib.user_encoding = self.user_encoding
 
253
        TestCaseInTempDir.tearDown(self)
 
254
 
 
255
    def create_branch(self):
 
256
        bzr = self.run_bzr
 
257
        bzr('init')
 
258
        open('a', 'wb').write('some stuff\n')
 
259
        bzr('add', 'a')
 
260
        bzr('commit', '-m', self._message)
 
261
 
 
262
    def try_encoding(self, encoding, fail=False):
 
263
        bzr = self.run_bzr
 
264
        if fail:
 
265
            self.assertRaises(UnicodeEncodeError,
 
266
                self._mu.encode, encoding)
 
267
            encoded_msg = self._message.encode(encoding, 'replace')
 
268
        else:
 
269
            encoded_msg = self._message.encode(encoding)
 
270
 
 
271
        old_encoding = bzrlib.user_encoding
 
272
        # This test requires that 'run_bzr' uses the current
 
273
        # bzrlib, because we override user_encoding, and expect
 
274
        # it to be used
 
275
        try:
 
276
            bzrlib.user_encoding = 'ascii'
 
277
            # We should be able to handle any encoding
 
278
            out, err = bzr('log', encoding=encoding)
 
279
            if not fail:
 
280
                # Make sure we wrote mu as we expected it to exist
 
281
                self.assertNotEqual(-1, out.find(encoded_msg))
 
282
                out_unicode = out.decode(encoding)
 
283
                self.assertNotEqual(-1, out_unicode.find(self._message))
 
284
            else:
 
285
                self.assertNotEqual(-1, out.find('Message with ?'))
 
286
        finally:
 
287
            bzrlib.user_encoding = old_encoding
 
288
 
 
289
    def test_log_handles_encoding(self):
 
290
        self.create_branch()
 
291
 
 
292
        for encoding in self.good_encodings:
 
293
            self.try_encoding(encoding)
 
294
 
 
295
    def test_log_handles_bad_encoding(self):
 
296
        self.create_branch()
 
297
 
 
298
        for encoding in self.bad_encodings:
 
299
            self.try_encoding(encoding, fail=True)
 
300
 
 
301
    def test_stdout_encoding(self):
 
302
        bzr = self.run_bzr
 
303
        bzrlib.user_encoding = "cp1251"
 
304
 
 
305
        bzr('init')
 
306
        self.build_tree(['a'])
 
307
        bzr('add', 'a')
 
308
        bzr('commit', '-m', u'\u0422\u0435\u0441\u0442')
 
309
        stdout, stderr = self.run_bzr('log', encoding='cp866')
 
310
 
 
311
        message = stdout.splitlines()[-1]
 
312
 
 
313
        # explanation of the check:
 
314
        # u'\u0422\u0435\u0441\u0442' is word 'Test' in russian
 
315
        # in cp866  encoding this is string '\x92\xa5\xe1\xe2'
 
316
        # in cp1251 encoding this is string '\xd2\xe5\xf1\xf2'
 
317
        # This test should check that output of log command
 
318
        # encoded to sys.stdout.encoding
 
319
        test_in_cp866 = '\x92\xa5\xe1\xe2'
 
320
        test_in_cp1251 = '\xd2\xe5\xf1\xf2'
 
321
        # Make sure the log string is encoded in cp866
 
322
        self.assertEquals(test_in_cp866, message[2:])
 
323
        # Make sure the cp1251 string is not found anywhere
 
324
        self.assertEquals(-1, stdout.find(test_in_cp1251))
 
325
 
 
326
 
 
327
class TestLogFile(TestCaseWithTransport):
 
328
 
 
329
    def test_log_local_branch_file(self):
 
330
        """We should be able to log files in local treeless branches"""
 
331
        tree = self.make_branch_and_tree('tree')
 
332
        self.build_tree(['tree/file'])
 
333
        tree.add('file')
 
334
        tree.commit('revision 1')
 
335
        tree.bzrdir.destroy_workingtree()
 
336
        self.run_bzr('log', 'tree/file')
 
337
 
 
338
    def test_log_file(self):
 
339
        """The log for a particular file should only list revs for that file"""
 
340
        tree = self.make_branch_and_tree('parent')
 
341
        self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
 
342
        tree.add('file1')
 
343
        tree.commit('add file1')
 
344
        tree.add('file2')
 
345
        tree.commit('add file2')
 
346
        tree.add('file3')
 
347
        tree.commit('add file3')
 
348
        self.run_bzr('branch', 'parent', 'child')
 
349
        print >> file('child/file2', 'wb'), 'hello'
 
350
        self.run_bzr('commit', '-m', 'branch 1', 'child')
 
351
        os.chdir('parent')
 
352
        self.run_bzr('merge', '../child')
 
353
        self.run_bzr('commit', '-m', 'merge child branch')
 
354
        
 
355
        log = self.run_bzr('log', 'file1')[0]
 
356
        self.assertContainsRe(log, 'revno: 1\n')
 
357
        self.assertNotContainsRe(log, 'revno: 2\n')
 
358
        self.assertNotContainsRe(log, 'revno: 3\n')
 
359
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
360
        self.assertNotContainsRe(log, 'revno: 4\n')
 
361
        log = self.run_bzr('log', 'file2')[0]
 
362
        self.assertNotContainsRe(log, 'revno: 1\n')
 
363
        self.assertContainsRe(log, 'revno: 2\n')
 
364
        self.assertNotContainsRe(log, 'revno: 3\n')
 
365
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
366
        self.assertContainsRe(log, 'revno: 4\n')
 
367
        log = self.run_bzr('log', 'file3')[0]
 
368
        self.assertNotContainsRe(log, 'revno: 1\n')
 
369
        self.assertNotContainsRe(log, 'revno: 2\n')
 
370
        self.assertContainsRe(log, 'revno: 3\n')
 
371
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
372
        self.assertNotContainsRe(log, 'revno: 4\n')