~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Robert Collins
  • Date: 2008-08-20 02:07:36 UTC
  • mfrom: (3640 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3682.
  • Revision ID: robertc@robertcollins.net-20080820020736-g2xe4921zzxtymle
Merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 by Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
# -*- coding: utf-8 -*-
3
 
 
 
3
#
4
4
# This program is free software; you can redistribute it and/or modify
5
5
# it under the terms of the GNU General Public License as published by
6
6
# the Free Software Foundation; either version 2 of the License, or
7
7
# (at your option) any later version.
8
 
 
 
8
#
9
9
# This program is distributed in the hope that it will be useful,
10
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
12
# GNU General Public License for more details.
13
 
 
 
13
#
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
22
 
23
23
import bzrlib
24
24
from bzrlib.tests.blackbox import ExternalBase
25
 
from bzrlib.tests import TestCaseInTempDir
 
25
from bzrlib.tests import TestCaseInTempDir, TestCaseWithTransport
 
26
from bzrlib.tests.test_log import (
 
27
    normalize_log,
 
28
    )
 
29
from bzrlib.tests import test_log
 
30
 
 
31
 
 
32
class TestCaseWithoutPropsHandler(ExternalBase, test_log.TestCaseWithoutPropsHandler):
 
33
    pass
26
34
 
27
35
 
28
36
class TestLog(ExternalBase):
29
37
 
30
 
    def _prepare(self):
31
 
        self.runbzr("init")
32
 
        self.build_tree(['hello.txt', 'goodbye.txt', 'meep.txt'])
33
 
        self.runbzr("add hello.txt")
34
 
        self.runbzr("commit -m message1 hello.txt")
35
 
        self.runbzr("add goodbye.txt")
36
 
        self.runbzr("commit -m message2 goodbye.txt")
37
 
        self.runbzr("add meep.txt")
38
 
        self.runbzr("commit -m message3 meep.txt")
39
 
        self.full_log = self.runbzr("log")[0]
 
38
    def _prepare(self, path='.', format=None):
 
39
        tree = self.make_branch_and_tree(path, format=format)
 
40
        self.build_tree(
 
41
            [path + '/hello.txt', path + '/goodbye.txt', path + '/meep.txt'])
 
42
        tree.add('hello.txt')
 
43
        tree.commit(message='message1')
 
44
        tree.add('goodbye.txt')
 
45
        tree.commit(message='message2')
 
46
        tree.add('meep.txt')
 
47
        tree.commit(message='message3')
 
48
        self.full_log = self.run_bzr(["log", path])[0]
 
49
        return tree
40
50
 
41
51
    def test_log_null_end_revspec(self):
42
52
        self._prepare()
47
57
        self.assertTrue('message:\n  message2\n' in self.full_log)
48
58
        self.assertTrue('message:\n  message3\n' in self.full_log)
49
59
 
50
 
        log = self.runbzr("log -r 1..")[0]
51
 
        self.assertEquals(log, self.full_log)
 
60
        log = self.run_bzr("log -r 1..")[0]
 
61
        self.assertEqualDiff(log, self.full_log)
52
62
 
53
63
    def test_log_null_begin_revspec(self):
54
64
        self._prepare()
55
 
        log = self.runbzr("log -r ..3")[0]
56
 
        self.assertEquals(self.full_log, log)
 
65
        log = self.run_bzr("log -r ..3")[0]
 
66
        self.assertEqualDiff(self.full_log, log)
57
67
 
58
68
    def test_log_null_both_revspecs(self):
59
69
        self._prepare()
60
 
        log = self.runbzr("log -r ..")[0]
61
 
        self.assertEquals(self.full_log, log)
 
70
        log = self.run_bzr("log -r ..")[0]
 
71
        self.assertEqualDiff(self.full_log, log)
 
72
 
 
73
    def test_log_zero_revspec(self):
 
74
        self._prepare()
 
75
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
 
76
                           ['log', '-r0'])
 
77
 
 
78
    def test_log_zero_begin_revspec(self):
 
79
        self._prepare()
 
80
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
 
81
                           ['log', '-r0..2'])
 
82
 
 
83
    def test_log_zero_end_revspec(self):
 
84
        self._prepare()
 
85
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
 
86
                           ['log', '-r-2..0'])
 
87
 
 
88
    def test_log_unsupported_timezone(self):
 
89
        self._prepare()
 
90
        self.run_bzr_error('bzr: ERROR: Unsupported timezone format "foo", '
 
91
                           'options are "utc", "original", "local".',
 
92
                           ['log', '--timezone', 'foo'])
62
93
 
63
94
    def test_log_negative_begin_revspec_full_log(self):
64
95
        self._prepare()
65
 
        log = self.runbzr("log -r -3..")[0]
66
 
        self.assertEquals(self.full_log, log)
 
96
        log = self.run_bzr("log -r -3..")[0]
 
97
        self.assertEqualDiff(self.full_log, log)
67
98
 
68
99
    def test_log_negative_both_revspec_full_log(self):
69
100
        self._prepare()
70
 
        log = self.runbzr("log -r -3..-1")[0]
71
 
        self.assertEquals(self.full_log, log)
 
101
        log = self.run_bzr("log -r -3..-1")[0]
 
102
        self.assertEqualDiff(self.full_log, log)
72
103
 
73
104
    def test_log_negative_both_revspec_partial(self):
74
105
        self._prepare()
75
 
        log = self.runbzr("log -r -3..-2")[0]
 
106
        log = self.run_bzr("log -r -3..-2")[0]
76
107
        self.assertTrue('revno: 1\n' in log)
77
108
        self.assertTrue('revno: 2\n' in log)
78
109
        self.assertTrue('revno: 3\n' not in log)
79
110
 
80
111
    def test_log_negative_begin_revspec(self):
81
112
        self._prepare()
82
 
        log = self.runbzr("log -r -2..")[0]
 
113
        log = self.run_bzr("log -r -2..")[0]
83
114
        self.assertTrue('revno: 1\n' not in log)
84
115
        self.assertTrue('revno: 2\n' in log)
85
116
        self.assertTrue('revno: 3\n' in log)
86
117
 
87
 
    def test_log_postive_revspecs(self):
88
 
        self._prepare()
89
 
        log = self.runbzr("log -r 1..3")[0]
90
 
        self.assertEquals(self.full_log, log)
91
 
 
92
 
 
93
 
class TestLogMerges(ExternalBase):
 
118
    def test_log_positive_revspecs(self):
 
119
        self._prepare()
 
120
        log = self.run_bzr("log -r 1..3")[0]
 
121
        self.assertEqualDiff(self.full_log, log)
 
122
 
 
123
    def test_log_reversed_revspecs(self):
 
124
        self._prepare()
 
125
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
 
126
                            'the end revision.\n',),
 
127
                           ['log', '-r3..1'])
 
128
 
 
129
    def test_log_revno_n_path(self):
 
130
        self._prepare(path='branch1')
 
131
        self._prepare(path='branch2')
 
132
        log = self.run_bzr("log -r revno:2:branch1..revno:3:branch2",
 
133
                          retcode=3)[0]
 
134
        log = self.run_bzr("log -r revno:1:branch2..revno:3:branch2")[0]
 
135
        self.assertEqualDiff(self.full_log, log)
 
136
        log = self.run_bzr("log -r revno:1:branch2")[0]
 
137
        self.assertTrue('revno: 1\n' in log)
 
138
        self.assertTrue('revno: 2\n' not in log)
 
139
        self.assertTrue('branch nick: branch2\n' in log)
 
140
        self.assertTrue('branch nick: branch1\n' not in log)
 
141
        
 
142
    def test_log_nonexistent_file(self):
 
143
        # files that don't exist in either the basis tree or working tree
 
144
        # should give an error
 
145
        wt = self.make_branch_and_tree('.')
 
146
        out, err = self.run_bzr('log does-not-exist', retcode=3)
 
147
        self.assertContainsRe(
 
148
            err, 'Path does not have any revision history: does-not-exist')
 
149
 
 
150
    def test_log_with_tags(self):
 
151
        tree = self._prepare(format='dirstate-tags')
 
152
        branch = tree.branch
 
153
        branch.tags.set_tag('tag1', branch.get_rev_id(1))
 
154
        branch.tags.set_tag('tag1.1', branch.get_rev_id(1))
 
155
        branch.tags.set_tag('tag3', branch.last_revision()) 
 
156
        
 
157
        log = self.run_bzr("log -r-1")[0]
 
158
        self.assertTrue('tags: tag3' in log)
 
159
 
 
160
        log = self.run_bzr("log -r1")[0]
 
161
        # I guess that we can't know the order of tags in the output
 
162
        # since dicts are unordered, need to check both possibilities
 
163
        self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)')
 
164
 
 
165
    def test_merged_log_with_tags(self):
 
166
        branch1_tree = self._prepare(path='branch1', format='dirstate-tags')
 
167
        branch1 = branch1_tree.branch
 
168
        branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
 
169
        branch1_tree.commit(message='foobar', allow_pointless=True)
 
170
        branch1.tags.set_tag('tag1', branch1.last_revision())
 
171
        os.chdir('branch2')
 
172
        self.run_bzr('merge ../branch1') # tags don't propagate otherwise
 
173
        branch2_tree.commit(message='merge branch 1')
 
174
        log = self.run_bzr("log -r-1")[0]
 
175
        self.assertContainsRe(log, r'    tags: tag1')
 
176
        log = self.run_bzr("log -r3.1.1")[0]
 
177
        self.assertContainsRe(log, r'tags: tag1')
 
178
 
 
179
    def test_log_limit(self):
 
180
        self._prepare()
 
181
        log = self.run_bzr("log --limit 2")[0]
 
182
        self.assertNotContainsRe(log, r'revno: 1\n')
 
183
        self.assertContainsRe(log, r'revno: 2\n')
 
184
        self.assertContainsRe(log, r'revno: 3\n')
 
185
 
 
186
    def test_log_limit_short(self):
 
187
        self._prepare()
 
188
        log = self.run_bzr("log -l 2")[0]
 
189
        self.assertNotContainsRe(log, r'revno: 1\n')
 
190
        self.assertContainsRe(log, r'revno: 2\n')
 
191
        self.assertContainsRe(log, r'revno: 3\n')
 
192
 
 
193
 
 
194
class TestLogMerges(TestCaseWithoutPropsHandler):
 
195
 
 
196
    def _prepare(self):
 
197
        parent_tree = self.make_branch_and_tree('parent')
 
198
        parent_tree.commit(message='first post', allow_pointless=True)
 
199
        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
 
200
        child_tree.commit(message='branch 1', allow_pointless=True)
 
201
        smaller_tree = \
 
202
                child_tree.bzrdir.sprout('smallerchild').open_workingtree()
 
203
        smaller_tree.commit(message='branch 2', allow_pointless=True)
 
204
        child_tree.merge_from_branch(smaller_tree.branch)
 
205
        child_tree.commit(message='merge branch 2')
 
206
        parent_tree.merge_from_branch(child_tree.branch)
 
207
        parent_tree.commit(message='merge branch 1')
 
208
        os.chdir('parent')
94
209
 
95
210
    def test_merges_are_indented_by_level(self):
96
 
        self.build_tree(['parent/'])
97
 
        self.run_bzr('init', 'parent')
98
 
        self.run_bzr('commit', '-m', 'first post', '--unchanged', 'parent')
99
 
        self.run_bzr('branch', 'parent', 'child')
100
 
        self.run_bzr('commit', '-m', 'branch 1', '--unchanged', 'child')
101
 
        self.run_bzr('branch', 'child', 'smallerchild')
102
 
        self.run_bzr('commit', '-m', 'branch 2', '--unchanged', 'smallerchild')
103
 
        os.chdir('child')
104
 
        self.run_bzr('merge', '../smallerchild')
105
 
        self.run_bzr('commit', '-m', 'merge branch 2')
106
 
        os.chdir('../parent')
107
 
        self.run_bzr('merge', '../child')
108
 
        self.run_bzr('commit', '-m', 'merge branch 1')
 
211
        self._prepare()
109
212
        out,err = self.run_bzr('log')
110
 
        # the log will look something like:
111
 
#        self.assertEqual("""\
112
 
#------------------------------------------------------------
113
 
#revno: 2
114
 
#committer: Robert Collins <foo@example.com>
115
 
#branch nick: parent
116
 
#timestamp: Tue 2006-03-28 22:31:40 +1100
117
 
#message:
118
 
#  merge branch 1
119
 
#    ------------------------------------------------------------
120
 
#    merged: foo@example.com-20060328113140-91f43cfb46dc2863
121
 
#    committer: Robert Collins <foo@example.com>
122
 
#    branch nick: child
123
 
#    timestamp: Tue 2006-03-28 22:31:40 +1100
124
 
#    message:
125
 
#      merge branch 2
126
 
#        ------------------------------------------------------------
127
 
#        merged: foo@example.com-20060328113140-1ba24f850a0ef573
128
 
#        committer: Robert Collins <foo@example.com>
129
 
#        branch nick: smallerchild
130
 
#        timestamp: Tue 2006-03-28 22:31:40 +1100
131
 
#        message:
132
 
#          branch 2
133
 
#    ------------------------------------------------------------
134
 
#    merged: foo@example.com-20060328113140-5749a4757a8ac792
135
 
#    committer: Robert Collins <foo@example.com>
136
 
#    branch nick: child
137
 
#    timestamp: Tue 2006-03-28 22:31:40 +1100
138
 
#    message:
139
 
#      branch 1
140
 
#------------------------------------------------------------
141
 
#revno: 1
142
 
#committer: Robert Collins <foo@example.com>
143
 
#branch nick: parent
144
 
#timestamp: Tue 2006-03-28 22:31:39 +1100
145
 
#message:
146
 
#  first post
147
 
#""", out)
148
 
        # but we dont have a nice pattern matcher hooked up yet, so:
149
 
        # we check for the indenting of the commit message:
150
 
        self.assertTrue('  merge branch 1' in out)
151
 
        self.assertTrue('      merge branch 2' in out)
152
 
        self.assertTrue('          branch 2' in out)
153
 
        self.assertTrue('      branch 1' in out)
154
 
        self.assertTrue('  first post' in out)
155
 
        self.assertEqual('', err)
156
 
 
157
 
 
 
213
        self.assertEqual('', err)
 
214
        log = normalize_log(out)
 
215
        self.assertEqualDiff(log, """\
 
216
------------------------------------------------------------
 
217
revno: 2
 
218
committer: Lorem Ipsum <test@example.com>
 
219
branch nick: parent
 
220
timestamp: Just now
 
221
message:
 
222
  merge branch 1
 
223
    ------------------------------------------------------------
 
224
    revno: 1.1.2
 
225
    committer: Lorem Ipsum <test@example.com>
 
226
    branch nick: child
 
227
    timestamp: Just now
 
228
    message:
 
229
      merge branch 2
 
230
        ------------------------------------------------------------
 
231
        revno: 1.2.1
 
232
        committer: Lorem Ipsum <test@example.com>
 
233
        branch nick: smallerchild
 
234
        timestamp: Just now
 
235
        message:
 
236
          branch 2
 
237
    ------------------------------------------------------------
 
238
    revno: 1.1.1
 
239
    committer: Lorem Ipsum <test@example.com>
 
240
    branch nick: child
 
241
    timestamp: Just now
 
242
    message:
 
243
      branch 1
 
244
------------------------------------------------------------
 
245
revno: 1
 
246
committer: Lorem Ipsum <test@example.com>
 
247
branch nick: parent
 
248
timestamp: Just now
 
249
message:
 
250
  first post
 
251
""")
 
252
 
 
253
    def test_merges_single_merge_rev(self):
 
254
        self._prepare()
 
255
        out,err = self.run_bzr('log -r1.1.2')
 
256
        self.assertEqual('', err)
 
257
        log = normalize_log(out)
 
258
        self.assertEqualDiff(log, """\
 
259
------------------------------------------------------------
 
260
revno: 1.1.2
 
261
committer: Lorem Ipsum <test@example.com>
 
262
branch nick: child
 
263
timestamp: Just now
 
264
message:
 
265
  merge branch 2
 
266
    ------------------------------------------------------------
 
267
    revno: 1.2.1
 
268
    committer: Lorem Ipsum <test@example.com>
 
269
    branch nick: smallerchild
 
270
    timestamp: Just now
 
271
    message:
 
272
      branch 2
 
273
""")
 
274
 
 
275
    def test_merges_partial_range(self):
 
276
        self._prepare()
 
277
        out,err = self.run_bzr('log -r1.1.1..1.1.2')
 
278
        self.assertEqual('', err)
 
279
        log = normalize_log(out)
 
280
        self.assertEqualDiff(log, """\
 
281
------------------------------------------------------------
 
282
revno: 1.1.2
 
283
committer: Lorem Ipsum <test@example.com>
 
284
branch nick: child
 
285
timestamp: Just now
 
286
message:
 
287
  merge branch 2
 
288
    ------------------------------------------------------------
 
289
    revno: 1.2.1
 
290
    committer: Lorem Ipsum <test@example.com>
 
291
    branch nick: smallerchild
 
292
    timestamp: Just now
 
293
    message:
 
294
      branch 2
 
295
------------------------------------------------------------
 
296
revno: 1.1.1
 
297
committer: Lorem Ipsum <test@example.com>
 
298
branch nick: child
 
299
timestamp: Just now
 
300
message:
 
301
  branch 1
 
302
""")
 
303
 
 
304
    def test_merges_nonsupporting_formatter(self):
 
305
        self._prepare()
 
306
        err_msg = 'Selected log formatter only supports mainline revisions.'
 
307
        # The single revision case is tested in the core tests
 
308
        # since all standard formatters support single merge revisions.
 
309
        out,err = self.run_bzr('log --short -r1..1.1.2', retcode=3)
 
310
        self.assertContainsRe(err, err_msg)
 
311
        out,err = self.run_bzr('log --short -r1.1.1..1.1.2', retcode=3)
 
312
        self.assertContainsRe(err, err_msg)
 
313
 
 
314
 
158
315
class TestLogEncodings(TestCaseInTempDir):
159
316
 
160
317
    _mu = u'\xb5'
188
345
        bzr = self.run_bzr
189
346
        bzr('init')
190
347
        open('a', 'wb').write('some stuff\n')
191
 
        bzr('add', 'a')
192
 
        bzr('commit', '-m', self._message)
 
348
        bzr('add a')
 
349
        bzr(['commit', '-m', self._message])
193
350
 
194
351
    def try_encoding(self, encoding, fail=False):
195
352
        bzr = self.run_bzr
236
393
 
237
394
        bzr('init')
238
395
        self.build_tree(['a'])
239
 
        bzr('add', 'a')
240
 
        bzr('commit', '-m', u'\u0422\u0435\u0441\u0442')
 
396
        bzr('add a')
 
397
        bzr(['commit', '-m', u'\u0422\u0435\u0441\u0442'])
241
398
        stdout, stderr = self.run_bzr('log', encoding='cp866')
242
399
 
243
400
        message = stdout.splitlines()[-1]
255
412
        # Make sure the cp1251 string is not found anywhere
256
413
        self.assertEquals(-1, stdout.find(test_in_cp1251))
257
414
 
 
415
 
 
416
class TestLogFile(TestCaseWithTransport):
 
417
 
 
418
    def test_log_local_branch_file(self):
 
419
        """We should be able to log files in local treeless branches"""
 
420
        tree = self.make_branch_and_tree('tree')
 
421
        self.build_tree(['tree/file'])
 
422
        tree.add('file')
 
423
        tree.commit('revision 1')
 
424
        tree.bzrdir.destroy_workingtree()
 
425
        self.run_bzr('log tree/file')
 
426
 
 
427
    def test_log_file(self):
 
428
        """The log for a particular file should only list revs for that file"""
 
429
        tree = self.make_branch_and_tree('parent')
 
430
        self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
 
431
        tree.add('file1')
 
432
        tree.commit('add file1')
 
433
        tree.add('file2')
 
434
        tree.commit('add file2')
 
435
        tree.add('file3')
 
436
        tree.commit('add file3')
 
437
        child_tree = tree.bzrdir.sprout('child').open_workingtree()
 
438
        self.build_tree_contents([('child/file2', 'hello')])
 
439
        child_tree.commit(message='branch 1')
 
440
        tree.merge_from_branch(child_tree.branch)
 
441
        tree.commit(message='merge child branch')
 
442
        os.chdir('parent')
 
443
        log = self.run_bzr('log file1')[0]
 
444
        self.assertContainsRe(log, 'revno: 1\n')
 
445
        self.assertNotContainsRe(log, 'revno: 2\n')
 
446
        self.assertNotContainsRe(log, 'revno: 3\n')
 
447
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
448
        self.assertNotContainsRe(log, 'revno: 4\n')
 
449
        log = self.run_bzr('log file2')[0]
 
450
        self.assertNotContainsRe(log, 'revno: 1\n')
 
451
        self.assertContainsRe(log, 'revno: 2\n')
 
452
        self.assertNotContainsRe(log, 'revno: 3\n')
 
453
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
454
        self.assertContainsRe(log, 'revno: 4\n')
 
455
        log = self.run_bzr('log file3')[0]
 
456
        self.assertNotContainsRe(log, 'revno: 1\n')
 
457
        self.assertNotContainsRe(log, 'revno: 2\n')
 
458
        self.assertContainsRe(log, 'revno: 3\n')
 
459
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
460
        self.assertNotContainsRe(log, 'revno: 4\n')
 
461
        log = self.run_bzr('log -r3.1.1 file2')[0]
 
462
        self.assertNotContainsRe(log, 'revno: 1\n')
 
463
        self.assertNotContainsRe(log, 'revno: 2\n')
 
464
        self.assertNotContainsRe(log, 'revno: 3\n')
 
465
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
466
        self.assertNotContainsRe(log, 'revno: 4\n')
 
467
        log = self.run_bzr('log -r4 file2')[0]
 
468
        self.assertNotContainsRe(log, 'revno: 1\n')
 
469
        self.assertNotContainsRe(log, 'revno: 2\n')
 
470
        self.assertNotContainsRe(log, 'revno: 3\n')
 
471
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
472
        self.assertContainsRe(log, 'revno: 4\n')
 
473
        log = self.run_bzr('log -r3.. file2')[0]
 
474
        self.assertNotContainsRe(log, 'revno: 1\n')
 
475
        self.assertNotContainsRe(log, 'revno: 2\n')
 
476
        self.assertNotContainsRe(log, 'revno: 3\n')
 
477
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
478
        self.assertContainsRe(log, 'revno: 4\n')
 
479
        log = self.run_bzr('log -r..3 file2')[0]
 
480
        self.assertNotContainsRe(log, 'revno: 1\n')
 
481
        self.assertContainsRe(log, 'revno: 2\n')
 
482
        self.assertNotContainsRe(log, 'revno: 3\n')
 
483
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
484
        self.assertNotContainsRe(log, 'revno: 4\n')