~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-04-09 20:23:07 UTC
  • mfrom: (4265.1.4 bbc-merge)
  • Revision ID: pqm@pqm.ubuntu.com-20090409202307-n0depb16qepoe21o
(jam) Change _fetch_uses_deltas = False for CHK repos until we can
        write a better fix.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
"""Black-box tests for bzr log."""
19
19
 
20
 
import os
21
 
import re
 
20
import os, re
22
21
 
23
 
from bzrlib import (
24
 
    osutils,
25
 
    tests,
 
22
from bzrlib import osutils
 
23
from bzrlib.tests.blackbox import ExternalBase
 
24
from bzrlib.tests import KnownFailure, TestCaseInTempDir, TestCaseWithTransport
 
25
from bzrlib.tests.test_log import (
 
26
    normalize_log,
26
27
    )
27
28
from bzrlib.tests import test_log
28
29
 
29
30
 
30
 
class TestLog(tests.TestCaseWithTransport):
31
 
 
32
 
    def setUp(self):
33
 
        super(TestLog, self).setUp()
34
 
        self.timezone = 0 # UTC
35
 
        self.timestamp = 1132617600 # Mon 2005-11-22 00:00:00 +0000
36
 
 
37
 
    def make_minimal_branch(self, path='.', format=None):
38
 
        tree = self.make_branch_and_tree(path, format=format)
39
 
        self.build_tree([path + '/hello.txt'])
40
 
        tree.add('hello.txt')
41
 
        tree.commit(message='message1')
42
 
        return tree
43
 
 
44
 
    def make_linear_branch(self, path='.', format=None):
 
31
class TestCaseWithoutPropsHandler(ExternalBase,
 
32
                                  test_log.TestCaseWithoutPropsHandler):
 
33
    pass
 
34
 
 
35
 
 
36
class TestLog(ExternalBase):
 
37
 
 
38
    def _prepare(self, path='.', format=None):
45
39
        tree = self.make_branch_and_tree(path, format=format)
46
40
        self.build_tree(
47
41
            [path + '/hello.txt', path + '/goodbye.txt', path + '/meep.txt'])
51
45
        tree.commit(message='message2')
52
46
        tree.add('meep.txt')
53
47
        tree.commit(message='message3')
54
 
        return tree
55
 
 
56
 
    def make_merged_branch(self, path='.', format=None):
57
 
        tree = self.make_linear_branch(path, format)
58
 
        tree2 = tree.bzrdir.sprout('tree2',
59
 
            revision_id=tree.branch.get_rev_id(1)).open_workingtree()
60
 
        tree2.commit(message='tree2 message2')
61
 
        tree2.commit(message='tree2 message3')
62
 
        tree.merge_from_branch(tree2.branch)
63
 
        tree.commit(message='merge')
64
 
        return tree
65
 
 
66
 
    def assertRevnos(self, log, must_have=(), must_not_have=()):
67
 
        """Check if revnos are in or not in the log output"""
68
 
        for revno in must_have:
69
 
            self.assertTrue(('revno: %s\n' % revno) in log,
70
 
                'Does not contain expected revno %s' % revno)
71
 
        for revno in must_not_have:
72
 
            self.assertFalse(('revno: %s\n' % revno) in log,
73
 
                'Contains unexpected revno %s' % revno)
74
 
 
75
 
    def commit_options(self):
76
 
        """Use some mostly fixed values for commits to simplify tests.
77
 
 
78
 
        Tests can use this function to get some commit attributes. The time
79
 
        stamp is incremented at each commit.
80
 
        """
81
 
        self.timestamp += 1 # 1 second between each commit
82
 
        return dict(committer='Lorem Ipsum <joe@foo.com>',
83
 
                 timezone=self.timezone,
84
 
                 timestamp=self.timestamp,
85
 
                 )
86
 
 
87
 
    def check_log(self, expected, args, working_dir='level0'):
88
 
        out, err = self.run_bzr(['log', '--timezone', 'utc'] + args,
89
 
                                working_dir=working_dir)
90
 
        self.assertEqual('', err)
91
 
        self.assertEqualDiff(expected, test_log.normalize_log(out))
92
 
 
93
 
 
94
 
class TestLogRevSpecs(TestLog):
 
48
        self.full_log = self.run_bzr(["log", path])[0]
 
49
        return tree
95
50
 
96
51
    def test_log_null_end_revspec(self):
97
 
        self.make_linear_branch()
98
 
        log = self.run_bzr(['log'])[0]
99
 
        self.assertTrue('revno: 1\n' in log)
100
 
        self.assertTrue('revno: 2\n' in log)
101
 
        self.assertTrue('revno: 3\n' in log)
102
 
        self.assertTrue('message:\n  message1\n' in log)
103
 
        self.assertTrue('message:\n  message2\n' in log)
104
 
        self.assertTrue('message:\n  message3\n' in log)
 
52
        self._prepare()
 
53
        self.assertTrue('revno: 1\n' in self.full_log)
 
54
        self.assertTrue('revno: 2\n' in self.full_log)
 
55
        self.assertTrue('revno: 3\n' in self.full_log)
 
56
        self.assertTrue('message:\n  message1\n' in self.full_log)
 
57
        self.assertTrue('message:\n  message2\n' in self.full_log)
 
58
        self.assertTrue('message:\n  message3\n' in self.full_log)
105
59
 
106
 
        full_log = self.run_bzr(['log'])[0]
107
60
        log = self.run_bzr("log -r 1..")[0]
108
 
        self.assertEqualDiff(log, full_log)
 
61
        self.assertEqualDiff(log, self.full_log)
109
62
 
110
63
    def test_log_null_begin_revspec(self):
111
 
        self.make_linear_branch()
112
 
        full_log = self.run_bzr(['log'])[0]
 
64
        self._prepare()
113
65
        log = self.run_bzr("log -r ..3")[0]
114
 
        self.assertEqualDiff(full_log, log)
 
66
        self.assertEqualDiff(self.full_log, log)
115
67
 
116
68
    def test_log_null_both_revspecs(self):
117
 
        self.make_linear_branch()
118
 
        full_log = self.run_bzr(['log'])[0]
 
69
        self._prepare()
119
70
        log = self.run_bzr("log -r ..")[0]
120
 
        self.assertEqualDiff(full_log, log)
 
71
        self.assertEqualDiff(self.full_log, log)
121
72
 
122
73
    def test_log_zero_revspec(self):
123
 
        self.make_minimal_branch()
124
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
74
        self._prepare()
 
75
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
125
76
                           ['log', '-r0'])
126
77
 
127
78
    def test_log_zero_begin_revspec(self):
128
 
        self.make_linear_branch()
129
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
79
        self._prepare()
 
80
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
130
81
                           ['log', '-r0..2'])
131
82
 
132
83
    def test_log_zero_end_revspec(self):
133
 
        self.make_linear_branch()
134
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
84
        self._prepare()
 
85
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
135
86
                           ['log', '-r-2..0'])
136
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'])
 
93
 
137
94
    def test_log_negative_begin_revspec_full_log(self):
138
 
        self.make_linear_branch()
139
 
        full_log = self.run_bzr(['log'])[0]
 
95
        self._prepare()
140
96
        log = self.run_bzr("log -r -3..")[0]
141
 
        self.assertEqualDiff(full_log, log)
 
97
        self.assertEqualDiff(self.full_log, log)
142
98
 
143
99
    def test_log_negative_both_revspec_full_log(self):
144
 
        self.make_linear_branch()
145
 
        full_log = self.run_bzr(['log'])[0]
 
100
        self._prepare()
146
101
        log = self.run_bzr("log -r -3..-1")[0]
147
 
        self.assertEqualDiff(full_log, log)
 
102
        self.assertEqualDiff(self.full_log, log)
148
103
 
149
104
    def test_log_negative_both_revspec_partial(self):
150
 
        self.make_linear_branch()
 
105
        self._prepare()
151
106
        log = self.run_bzr("log -r -3..-2")[0]
152
107
        self.assertTrue('revno: 1\n' in log)
153
108
        self.assertTrue('revno: 2\n' in log)
154
109
        self.assertTrue('revno: 3\n' not in log)
155
110
 
156
111
    def test_log_negative_begin_revspec(self):
157
 
        self.make_linear_branch()
 
112
        self._prepare()
158
113
        log = self.run_bzr("log -r -2..")[0]
159
114
        self.assertTrue('revno: 1\n' not in log)
160
115
        self.assertTrue('revno: 2\n' in log)
161
116
        self.assertTrue('revno: 3\n' in log)
162
117
 
163
118
    def test_log_positive_revspecs(self):
164
 
        self.make_linear_branch()
165
 
        full_log = self.run_bzr(['log'])[0]
 
119
        self._prepare()
166
120
        log = self.run_bzr("log -r 1..3")[0]
167
 
        self.assertEqualDiff(full_log, log)
168
 
 
169
 
    def test_log_dotted_revspecs(self):
170
 
        self.make_merged_branch()
171
 
        log = self.run_bzr("log -n0 -r 1..1.1.1")[0]
172
 
        self.assertRevnos(log, (1, '1.1.1'), (2, 3, '1.1.2', 4))
 
121
        self.assertEqualDiff(self.full_log, log)
173
122
 
174
123
    def test_log_reversed_revspecs(self):
175
 
        self.make_linear_branch()
 
124
        self._prepare()
176
125
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
177
126
                            'the end revision.\n',),
178
127
                           ['log', '-r3..1'])
179
128
 
180
 
    def test_log_reversed_dotted_revspecs(self):
181
 
        self.make_merged_branch()
182
 
        self.run_bzr_error(('bzr: ERROR: Start revision not found in '
183
 
                            'left-hand history of end revision.\n',),
184
 
                           "log -r 1.1.1..1")
185
 
 
186
129
    def test_log_revno_n_path(self):
187
 
        self.make_linear_branch('branch1')
188
 
        self.make_linear_branch('branch2')
189
 
        # Swapped revisions
190
 
        self.run_bzr("log -r revno:2:branch1..revno:3:branch2", retcode=3)[0]
191
 
        # Correct order
 
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]
192
134
        log = self.run_bzr("log -r revno:1:branch2..revno:3:branch2")[0]
193
 
        full_log = self.run_bzr(['log'], working_dir='branch2')[0]
194
 
        self.assertEqualDiff(full_log, log)
 
135
        self.assertEqualDiff(self.full_log, log)
195
136
        log = self.run_bzr("log -r revno:1:branch2")[0]
196
137
        self.assertTrue('revno: 1\n' in log)
197
138
        self.assertTrue('revno: 2\n' not in log)
199
140
        self.assertTrue('branch nick: branch1\n' not in log)
200
141
 
201
142
    def test_log_nonexistent_revno(self):
202
 
        self.make_minimal_branch()
203
 
        (out, err) = self.run_bzr_error(
204
 
            ["bzr: ERROR: Requested revision: '1234' "
205
 
             "does not exist in branch:"],
206
 
            ['log', '-r1234'])
 
143
        self._prepare()
 
144
        (out, err) = self.run_bzr_error(args="log -r 1234",
 
145
            error_regexes=["bzr: ERROR: Requested revision: '1234' "
 
146
                "does not exist in branch:"])
207
147
 
208
148
    def test_log_nonexistent_dotted_revno(self):
209
 
        self.make_minimal_branch()
210
 
        (out, err) = self.run_bzr_error(
211
 
            ["bzr: ERROR: Requested revision: '123.123' "
212
 
             "does not exist in branch:"],
213
 
            ['log',  '-r123.123'])
 
149
        self._prepare()
 
150
        (out, err) = self.run_bzr_error(args="log -r 123.123",
 
151
            error_regexes=["bzr: ERROR: Requested revision: '123.123' "
 
152
                "does not exist in branch:"])
214
153
 
215
154
    def test_log_change_revno(self):
216
 
        self.make_linear_branch()
 
155
        self._prepare()
217
156
        expected_log = self.run_bzr("log -r 1")[0]
218
157
        log = self.run_bzr("log -c 1")[0]
219
158
        self.assertEqualDiff(expected_log, log)
220
159
 
221
160
    def test_log_change_nonexistent_revno(self):
222
 
        self.make_minimal_branch()
223
 
        (out, err) = self.run_bzr_error(
224
 
            ["bzr: ERROR: Requested revision: '1234' "
225
 
             "does not exist in branch:"],
226
 
            ['log',  '-c1234'])
 
161
        self._prepare()
 
162
        (out, err) = self.run_bzr_error(args="log -c 1234",
 
163
            error_regexes=["bzr: ERROR: Requested revision: '1234' "
 
164
                "does not exist in branch:"])
227
165
 
228
166
    def test_log_change_nonexistent_dotted_revno(self):
229
 
        self.make_minimal_branch()
230
 
        (out, err) = self.run_bzr_error(
231
 
            ["bzr: ERROR: Requested revision: '123.123' "
232
 
             "does not exist in branch:"],
233
 
            ['log', '-c123.123'])
 
167
        self._prepare()
 
168
        (out, err) = self.run_bzr_error(args="log -c 123.123",
 
169
            error_regexes=["bzr: ERROR: Requested revision: '123.123' "
 
170
                "does not exist in branch:"])
234
171
 
235
 
    def test_log_change_single_revno_only(self):
236
 
        self.make_minimal_branch()
237
 
        self.run_bzr_error(['bzr: ERROR: Option --change does not'
238
 
                           ' accept revision ranges'],
 
172
    def test_log_change_single_revno(self):
 
173
        self._prepare()
 
174
        self.run_bzr_error('bzr: ERROR: Option --change does not'
 
175
                           ' accept revision ranges',
239
176
                           ['log', '--change', '2..3'])
240
177
 
241
178
    def test_log_change_incompatible_with_revision(self):
242
 
        self.run_bzr_error(['bzr: ERROR: --revision and --change'
243
 
                           ' are mutually exclusive'],
 
179
        self._prepare()
 
180
        self.run_bzr_error('bzr: ERROR: --revision and --change'
 
181
                           ' are mutually exclusive',
244
182
                           ['log', '--change', '2', '--revision', '3'])
245
183
 
246
184
    def test_log_nonexistent_file(self):
247
 
        self.make_minimal_branch()
248
185
        # files that don't exist in either the basis tree or working tree
249
186
        # should give an error
 
187
        wt = self.make_branch_and_tree('.')
250
188
        out, err = self.run_bzr('log does-not-exist', retcode=3)
251
 
        self.assertContainsRe(err,
252
 
                              'Path unknown at end or start of revision range: '
253
 
                              'does-not-exist')
 
189
        self.assertContainsRe(
 
190
            err, 'Path unknown at end or start of revision range: does-not-exist')
254
191
 
255
192
    def test_log_with_tags(self):
256
 
        tree = self.make_linear_branch(format='dirstate-tags')
 
193
        tree = self._prepare(format='dirstate-tags')
257
194
        branch = tree.branch
258
195
        branch.tags.set_tag('tag1', branch.get_rev_id(1))
259
196
        branch.tags.set_tag('tag1.1', branch.get_rev_id(1))
268
205
        self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)')
269
206
 
270
207
    def test_merged_log_with_tags(self):
271
 
        branch1_tree = self.make_linear_branch('branch1',
272
 
                                               format='dirstate-tags')
 
208
        branch1_tree = self._prepare(path='branch1', format='dirstate-tags')
273
209
        branch1 = branch1_tree.branch
274
210
        branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
275
211
        branch1_tree.commit(message='foobar', allow_pointless=True)
276
212
        branch1.tags.set_tag('tag1', branch1.last_revision())
277
 
        # tags don't propagate if we don't merge
278
 
        self.run_bzr('merge ../branch1', working_dir='branch2')
 
213
        os.chdir('branch2')
 
214
        self.run_bzr('merge ../branch1') # tags don't propagate otherwise
279
215
        branch2_tree.commit(message='merge branch 1')
280
 
        log = self.run_bzr("log -n0 -r-1", working_dir='branch2')[0]
 
216
        log = self.run_bzr("log -n0 -r-1")[0]
281
217
        self.assertContainsRe(log, r'    tags: tag1')
282
 
        log = self.run_bzr("log -n0 -r3.1.1", working_dir='branch2')[0]
 
218
        log = self.run_bzr("log -n0 -r3.1.1")[0]
283
219
        self.assertContainsRe(log, r'tags: tag1')
284
220
 
285
221
    def test_log_limit(self):
300
236
        self.assertContainsRe(log, r'revno: 10\n')
301
237
 
302
238
    def test_log_limit_short(self):
303
 
        self.make_linear_branch()
 
239
        self._prepare()
304
240
        log = self.run_bzr("log -l 2")[0]
305
241
        self.assertNotContainsRe(log, r'revno: 1\n')
306
242
        self.assertContainsRe(log, r'revno: 2\n')
311
247
        
312
248
        See https://bugs.launchpad.net/bzr/+bug/251352
313
249
        """
314
 
        self.make_minimal_branch()
 
250
        self._prepare()
315
251
        out, err = self.run_bzr(['log', '-m', '*'], retcode=3)
316
252
        self.assertEqual("bzr: ERROR: Invalid regular expression"
317
253
            " in log message filter"
320
256
        self.assertEqual('', out)
321
257
 
322
258
 
323
 
class TestLogTimeZone(TestLog):
324
 
 
325
 
    def test_log_unsupported_timezone(self):
326
 
        self.make_linear_branch()
327
 
        self.run_bzr_error(['bzr: ERROR: Unsupported timezone format "foo", '
328
 
                            'options are "utc", "original", "local".'],
329
 
                           ['log', '--timezone', 'foo'])
330
 
 
331
 
 
332
 
class TestLogVerbose(TestLog):
 
259
class TestLogVerbose(TestCaseWithTransport):
333
260
 
334
261
    def setUp(self):
335
262
        super(TestLogVerbose, self).setUp()
336
 
        self.make_minimal_branch()
 
263
        tree = self.make_branch_and_tree('.')
 
264
        self.build_tree(['hello.txt'])
 
265
        tree.add('hello.txt')
 
266
        tree.commit(message='message1')
337
267
 
338
268
    def assertUseShortDeltaFormat(self, cmd):
339
269
        log = self.run_bzr(cmd)[0]
364
294
        self.assertUseLongDeltaFormat(['log', '--long', '-vv'])
365
295
 
366
296
 
367
 
class TestLogMerges(TestLog):
368
 
 
369
 
    def setUp(self):
370
 
        super(TestLogMerges, self).setUp()
371
 
        self.make_branches_with_merges()
372
 
 
373
 
    def make_branches_with_merges(self):
374
 
        level0 = self.make_branch_and_tree('level0')
375
 
        level0.commit(message='in branch level0', **self.commit_options())
376
 
 
377
 
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
378
 
        level1.commit(message='in branch level1', **self.commit_options())
379
 
 
380
 
        level2 = level1.bzrdir.sprout('level2').open_workingtree()
381
 
        level2.commit(message='in branch level2', **self.commit_options())
382
 
 
383
 
        level1.merge_from_branch(level2.branch)
384
 
        level1.commit(message='merge branch level2', **self.commit_options())
385
 
 
386
 
        level0.merge_from_branch(level1.branch)
387
 
        level0.commit(message='merge branch level1', **self.commit_options())
 
297
class TestLogMerges(TestCaseWithoutPropsHandler):
 
298
 
 
299
    def _prepare(self):
 
300
        parent_tree = self.make_branch_and_tree('parent')
 
301
        parent_tree.commit(message='first post', allow_pointless=True)
 
302
        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
 
303
        child_tree.commit(message='branch 1', allow_pointless=True)
 
304
        smaller_tree = \
 
305
                child_tree.bzrdir.sprout('smallerchild').open_workingtree()
 
306
        smaller_tree.commit(message='branch 2', allow_pointless=True)
 
307
        child_tree.merge_from_branch(smaller_tree.branch)
 
308
        child_tree.commit(message='merge branch 2')
 
309
        parent_tree.merge_from_branch(child_tree.branch)
 
310
        parent_tree.commit(message='merge branch 1')
 
311
        os.chdir('parent')
 
312
 
 
313
    def _prepare_short(self):
 
314
        parent_tree = self.make_branch_and_tree('parent')
 
315
        parent_tree.commit(message='first post',
 
316
            timestamp=1132586700, timezone=36000,
 
317
            committer='Joe Foo <joe@foo.com>')
 
318
        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
 
319
        child_tree.commit(message='branch 1',
 
320
            timestamp=1132586800, timezone=36000,
 
321
            committer='Joe Foo <joe@foo.com>')
 
322
        smaller_tree = \
 
323
                child_tree.bzrdir.sprout('smallerchild').open_workingtree()
 
324
        smaller_tree.commit(message='branch 2',
 
325
            timestamp=1132586900, timezone=36000,
 
326
            committer='Joe Foo <joe@foo.com>')
 
327
        child_tree.merge_from_branch(smaller_tree.branch)
 
328
        child_tree.commit(message='merge branch 2',
 
329
            timestamp=1132587000, timezone=36000,
 
330
            committer='Joe Foo <joe@foo.com>')
 
331
        parent_tree.merge_from_branch(child_tree.branch)
 
332
        parent_tree.commit(message='merge branch 1',
 
333
            timestamp=1132587100, timezone=36000,
 
334
            committer='Joe Foo <joe@foo.com>')
 
335
        os.chdir('parent')
388
336
 
389
337
    def test_merges_are_indented_by_level(self):
390
 
        expected = """\
 
338
        self._prepare()
 
339
        out,err = self.run_bzr('log -n0')
 
340
        self.assertEqual('', err)
 
341
        log = normalize_log(out)
 
342
        self.assertEqualDiff(log, """\
391
343
------------------------------------------------------------
392
344
revno: 2 [merge]
393
345
committer: Lorem Ipsum <test@example.com>
394
 
branch nick: level0
 
346
branch nick: parent
395
347
timestamp: Just now
396
348
message:
397
 
  merge branch level1
 
349
  merge branch 1
398
350
    ------------------------------------------------------------
399
351
    revno: 1.1.2 [merge]
400
352
    committer: Lorem Ipsum <test@example.com>
401
 
    branch nick: level1
 
353
    branch nick: child
402
354
    timestamp: Just now
403
355
    message:
404
 
      merge branch level2
 
356
      merge branch 2
405
357
        ------------------------------------------------------------
406
358
        revno: 1.2.1
407
359
        committer: Lorem Ipsum <test@example.com>
408
 
        branch nick: level2
 
360
        branch nick: smallerchild
409
361
        timestamp: Just now
410
362
        message:
411
 
          in branch level2
 
363
          branch 2
412
364
    ------------------------------------------------------------
413
365
    revno: 1.1.1
414
366
    committer: Lorem Ipsum <test@example.com>
415
 
    branch nick: level1
 
367
    branch nick: child
416
368
    timestamp: Just now
417
369
    message:
418
 
      in branch level1
 
370
      branch 1
419
371
------------------------------------------------------------
420
372
revno: 1
421
373
committer: Lorem Ipsum <test@example.com>
422
 
branch nick: level0
 
374
branch nick: parent
423
375
timestamp: Just now
424
376
message:
425
 
  in branch level0
426
 
"""
427
 
        self.check_log(expected, ['-n0'])
 
377
  first post
 
378
""")
428
379
 
429
380
    def test_force_merge_revisions_off(self):
430
 
        expected = """\
 
381
        self._prepare()
 
382
        out,err = self.run_bzr('log --long -n1')
 
383
        self.assertEqual('', err)
 
384
        log = normalize_log(out)
 
385
        self.assertEqualDiff(log, """\
431
386
------------------------------------------------------------
432
387
revno: 2 [merge]
433
388
committer: Lorem Ipsum <test@example.com>
434
 
branch nick: level0
 
389
branch nick: parent
435
390
timestamp: Just now
436
391
message:
437
 
  merge branch level1
 
392
  merge branch 1
438
393
------------------------------------------------------------
439
394
revno: 1
440
395
committer: Lorem Ipsum <test@example.com>
441
 
branch nick: level0
 
396
branch nick: parent
442
397
timestamp: Just now
443
398
message:
444
 
  in branch level0
445
 
"""
446
 
        self.check_log(expected, ['--long', '-n1'])
 
399
  first post
 
400
------------------------------------------------------------
 
401
Use --levels 0 (or -n0) to see merged revisions.
 
402
""")
447
403
 
448
404
    def test_force_merge_revisions_on(self):
449
 
        expected = """\
450
 
    2 Lorem Ipsum\t2005-11-22 [merge]
451
 
      merge branch level1
452
 
 
453
 
          1.1.2 Lorem Ipsum\t2005-11-22 [merge]
454
 
                merge branch level2
455
 
 
456
 
              1.2.1 Lorem Ipsum\t2005-11-22
457
 
                    in branch level2
458
 
 
459
 
          1.1.1 Lorem Ipsum\t2005-11-22
460
 
                in branch level1
461
 
 
462
 
    1 Lorem Ipsum\t2005-11-22
463
 
      in branch level0
464
 
 
465
 
"""
466
 
        self.check_log(expected, ['--short', '-n0'])
467
 
 
468
 
    def test_include_merges(self):
469
 
        # Confirm --include-merges gives the same output as -n0
470
 
        out_im, err_im = self.run_bzr('log --include-merges',
471
 
                                      working_dir='level0')
472
 
        out_n0, err_n0 = self.run_bzr('log -n0', working_dir='level0')
473
 
        self.assertEqual('', err_im)
474
 
        self.assertEqual('', err_n0)
475
 
        self.assertEqual(out_im, out_n0)
 
405
        self._prepare_short()
 
406
        out,err = self.run_bzr('log --short -n0')
 
407
        self.assertEqual('', err)
 
408
        log = normalize_log(out)
 
409
        self.assertEqualDiff(log, """\
 
410
    2 Joe Foo\t2005-11-22 [merge]
 
411
      merge branch 1
 
412
 
 
413
          1.1.2 Joe Foo\t2005-11-22 [merge]
 
414
                merge branch 2
 
415
 
 
416
              1.2.1 Joe Foo\t2005-11-22
 
417
                    branch 2
 
418
 
 
419
          1.1.1 Joe Foo\t2005-11-22
 
420
                branch 1
 
421
 
 
422
    1 Joe Foo\t2005-11-22
 
423
      first post
 
424
 
 
425
""")
476
426
 
477
427
    def test_force_merge_revisions_N(self):
478
 
        expected = """\
479
 
    2 Lorem Ipsum\t2005-11-22 [merge]
480
 
      merge branch level1
481
 
 
482
 
          1.1.2 Lorem Ipsum\t2005-11-22 [merge]
483
 
                merge branch level2
484
 
 
485
 
          1.1.1 Lorem Ipsum\t2005-11-22
486
 
                in branch level1
487
 
 
488
 
    1 Lorem Ipsum\t2005-11-22
489
 
      in branch level0
490
 
 
491
 
"""
492
 
        self.check_log(expected, ['--short', '-n2'])
 
428
        self._prepare_short()
 
429
        out,err = self.run_bzr('log --short -n2')
 
430
        self.assertEqual('', err)
 
431
        log = normalize_log(out)
 
432
        self.assertEqualDiff(log, """\
 
433
    2 Joe Foo\t2005-11-22 [merge]
 
434
      merge branch 1
 
435
 
 
436
          1.1.2 Joe Foo\t2005-11-22 [merge]
 
437
                merge branch 2
 
438
 
 
439
          1.1.1 Joe Foo\t2005-11-22
 
440
                branch 1
 
441
 
 
442
    1 Joe Foo\t2005-11-22
 
443
      first post
 
444
 
 
445
""")
493
446
 
494
447
    def test_merges_single_merge_rev(self):
495
 
        expected = """\
 
448
        self._prepare()
 
449
        out,err = self.run_bzr('log -n0 -r1.1.2')
 
450
        self.assertEqual('', err)
 
451
        log = normalize_log(out)
 
452
        self.assertEqualDiff(log, """\
496
453
------------------------------------------------------------
497
454
revno: 1.1.2 [merge]
498
455
committer: Lorem Ipsum <test@example.com>
499
 
branch nick: level1
 
456
branch nick: child
500
457
timestamp: Just now
501
458
message:
502
 
  merge branch level2
 
459
  merge branch 2
503
460
    ------------------------------------------------------------
504
461
    revno: 1.2.1
505
462
    committer: Lorem Ipsum <test@example.com>
506
 
    branch nick: level2
 
463
    branch nick: smallerchild
507
464
    timestamp: Just now
508
465
    message:
509
 
      in branch level2
510
 
"""
511
 
        self.check_log(expected, ['-n0', '-r1.1.2'])
 
466
      branch 2
 
467
""")
512
468
 
513
469
    def test_merges_partial_range(self):
514
 
        expected = """\
 
470
        self._prepare()
 
471
        out, err = self.run_bzr('log -n0 -r1.1.1..1.1.2')
 
472
        self.assertEqual('', err)
 
473
        log = normalize_log(out)
 
474
        self.assertEqualDiff(log, """\
515
475
------------------------------------------------------------
516
476
revno: 1.1.2 [merge]
517
477
committer: Lorem Ipsum <test@example.com>
518
 
branch nick: level1
 
478
branch nick: child
519
479
timestamp: Just now
520
480
message:
521
 
  merge branch level2
 
481
  merge branch 2
522
482
    ------------------------------------------------------------
523
483
    revno: 1.2.1
524
484
    committer: Lorem Ipsum <test@example.com>
525
 
    branch nick: level2
 
485
    branch nick: smallerchild
526
486
    timestamp: Just now
527
487
    message:
528
 
      in branch level2
 
488
      branch 2
529
489
------------------------------------------------------------
530
490
revno: 1.1.1
531
491
committer: Lorem Ipsum <test@example.com>
532
 
branch nick: level1
 
492
branch nick: child
533
493
timestamp: Just now
534
494
message:
535
 
  in branch level1
536
 
"""
537
 
        self.check_log(expected, ['-n0', '-r1.1.1..1.1.2'])
538
 
 
539
 
 
540
 
class TestLogDiff(TestLog):
541
 
 
542
 
    def setUp(self):
543
 
        super(TestLogDiff, self).setUp()
544
 
        self.make_branch_with_diffs()
545
 
 
546
 
    def make_branch_with_diffs(self):
547
 
        level0 = self.make_branch_and_tree('level0')
548
 
        self.build_tree(['level0/file1', 'level0/file2'])
549
 
        level0.add('file1')
550
 
        level0.add('file2')
551
 
        level0.commit(message='in branch level0', **self.commit_options())
552
 
 
553
 
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
554
 
        self.build_tree_contents([('level1/file2', 'hello\n')])
555
 
        level1.commit(message='in branch level1', **self.commit_options())
556
 
        level0.merge_from_branch(level1.branch)
557
 
        level0.commit(message='merge branch level1', **self.commit_options())
 
495
  branch 1
 
496
""")
 
497
 
 
498
 
 
499
def subst_dates(string):
 
500
    """Replace date strings with constant values."""
 
501
    return re.sub(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-\+]\d{4}',
 
502
                  'YYYY-MM-DD HH:MM:SS +ZZZZ', string)
 
503
 
 
504
 
 
505
class TestLogDiff(TestCaseWithoutPropsHandler):
 
506
 
 
507
    def _prepare(self):
 
508
        parent_tree = self.make_branch_and_tree('parent')
 
509
        self.build_tree(['parent/file1', 'parent/file2'])
 
510
        parent_tree.add('file1')
 
511
        parent_tree.add('file2')
 
512
        parent_tree.commit(message='first post',
 
513
            timestamp=1132586655, timezone=36000,
 
514
            committer='Lorem Ipsum <test@example.com>')
 
515
        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
 
516
        self.build_tree_contents([('child/file2', 'hello\n')])
 
517
        child_tree.commit(message='branch 1',
 
518
            timestamp=1132586700, timezone=36000,
 
519
            committer='Lorem Ipsum <test@example.com>')
 
520
        parent_tree.merge_from_branch(child_tree.branch)
 
521
        parent_tree.commit(message='merge branch 1',
 
522
            timestamp=1132586800, timezone=36000,
 
523
            committer='Lorem Ipsum <test@example.com>')
 
524
        os.chdir('parent')
558
525
 
559
526
    def test_log_show_diff_long_with_merges(self):
 
527
        self._prepare()
560
528
        out,err = self.run_bzr('log -p -n0')
561
529
        self.assertEqual('', err)
562
 
        log = test_log.normalize_log(out)
563
 
        expected = """\
 
530
        log = normalize_log(out)
 
531
        self.assertEqualDiff(subst_dates(log), """\
564
532
------------------------------------------------------------
565
533
revno: 2 [merge]
566
534
committer: Lorem Ipsum <test@example.com>
567
 
branch nick: level0
 
535
branch nick: parent
568
536
timestamp: Just now
569
537
message:
570
 
  merge branch level1
 
538
  merge branch 1
571
539
diff:
572
540
=== modified file 'file2'
573
 
--- file2\t2005-11-22 00:00:01 +0000
574
 
+++ file2\t2005-11-22 00:00:02 +0000
 
541
--- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
542
+++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
575
543
@@ -1,1 +1,1 @@
576
 
-contents of level0/file2
 
544
-contents of parent/file2
577
545
+hello
578
546
    ------------------------------------------------------------
579
547
    revno: 1.1.1
580
548
    committer: Lorem Ipsum <test@example.com>
581
 
    branch nick: level1
 
549
    branch nick: child
582
550
    timestamp: Just now
583
551
    message:
584
 
      in branch level1
 
552
      branch 1
585
553
    diff:
586
554
    === modified file 'file2'
587
 
    --- file2\t2005-11-22 00:00:01 +0000
588
 
    +++ file2\t2005-11-22 00:00:02 +0000
 
555
    --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
556
    +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
589
557
    @@ -1,1 +1,1 @@
590
 
    -contents of level0/file2
 
558
    -contents of parent/file2
591
559
    +hello
592
560
------------------------------------------------------------
593
561
revno: 1
594
562
committer: Lorem Ipsum <test@example.com>
595
 
branch nick: level0
 
563
branch nick: parent
596
564
timestamp: Just now
597
565
message:
598
 
  in branch level0
 
566
  first post
599
567
diff:
600
568
=== added file 'file1'
601
 
--- file1\t1970-01-01 00:00:00 +0000
602
 
+++ file1\t2005-11-22 00:00:01 +0000
 
569
--- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
570
+++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
603
571
@@ -0,0 +1,1 @@
604
 
+contents of level0/file1
 
572
+contents of parent/file1
605
573
 
606
574
=== added file 'file2'
607
 
--- file2\t1970-01-01 00:00:00 +0000
608
 
+++ file2\t2005-11-22 00:00:01 +0000
 
575
--- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
576
+++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
609
577
@@ -0,0 +1,1 @@
610
 
+contents of level0/file2
611
 
"""
612
 
        self.check_log(expected, ['-p', '-n0'])
 
578
+contents of parent/file2
 
579
""")
613
580
 
614
581
    def test_log_show_diff_short(self):
615
 
        expected = """\
 
582
        self._prepare()
 
583
        out,err = self.run_bzr('log -p --short')
 
584
        self.assertEqual('', err)
 
585
        log = normalize_log(out)
 
586
        self.assertEqualDiff(subst_dates(log), """\
616
587
    2 Lorem Ipsum\t2005-11-22 [merge]
617
 
      merge branch level1
 
588
      merge branch 1
618
589
      === modified file 'file2'
619
 
      --- file2\t2005-11-22 00:00:01 +0000
620
 
      +++ file2\t2005-11-22 00:00:02 +0000
 
590
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
591
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
621
592
      @@ -1,1 +1,1 @@
622
 
      -contents of level0/file2
 
593
      -contents of parent/file2
623
594
      +hello
624
595
 
625
596
    1 Lorem Ipsum\t2005-11-22
626
 
      in branch level0
 
597
      first post
627
598
      === added file 'file1'
628
 
      --- file1\t1970-01-01 00:00:00 +0000
629
 
      +++ file1\t2005-11-22 00:00:01 +0000
 
599
      --- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
600
      +++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
630
601
      @@ -0,0 +1,1 @@
631
 
      +contents of level0/file1
 
602
      +contents of parent/file1
632
603
\x20\x20\x20\x20\x20\x20
633
604
      === added file 'file2'
634
 
      --- file2\t1970-01-01 00:00:00 +0000
635
 
      +++ file2\t2005-11-22 00:00:01 +0000
 
605
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
606
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
636
607
      @@ -0,0 +1,1 @@
637
 
      +contents of level0/file2
 
608
      +contents of parent/file2
638
609
 
639
 
Use --include-merges or -n0 to see merged revisions.
640
 
"""
641
 
        self.check_log(expected, ['-p', '--short'])
 
610
Use --levels 0 (or -n0) to see merged revisions.
 
611
""")
642
612
 
643
613
    def test_log_show_diff_line(self):
 
614
        self._prepare()
 
615
        out,err = self.run_bzr('log -p --line')
 
616
        self.assertEqual('', err)
 
617
        log = normalize_log(out)
644
618
        # Not supported by this formatter so expect plain output
645
 
        expected = """\
646
 
2: Lorem Ipsum 2005-11-22 [merge] merge branch level1
647
 
1: Lorem Ipsum 2005-11-22 in branch level0
648
 
"""
649
 
        self.check_log(expected, ['-p', '--line'])
650
 
 
651
 
    def test_log_show_diff_file1(self):
652
 
        """Only the diffs for the given file are to be shown"""
653
 
        expected = """\
654
 
    1 Lorem Ipsum\t2005-11-22
655
 
      in branch level0
656
 
      === added file 'file1'
657
 
      --- file1\t1970-01-01 00:00:00 +0000
658
 
      +++ file1\t2005-11-22 00:00:01 +0000
659
 
      @@ -0,0 +1,1 @@
660
 
      +contents of level0/file1
661
 
 
662
 
"""
663
 
        self.check_log(expected, ['-p', '--short', 'file1'])
664
 
 
665
 
    def test_log_show_diff_file2(self):
666
 
        """Only the diffs for the given file are to be shown"""
667
 
        expected = """\
 
619
        self.assertEqualDiff(subst_dates(log), """\
 
620
2: Lorem Ipsum 2005-11-22 [merge] merge branch 1
 
621
1: Lorem Ipsum 2005-11-22 first post
 
622
""")
 
623
 
 
624
    def test_log_show_diff_file(self):
 
625
        """Only the diffs for the given file are to be shown"""
 
626
        self._prepare()
 
627
        out,err = self.run_bzr('log -p --short file2')
 
628
        self.assertEqual('', err)
 
629
        log = normalize_log(out)
 
630
        self.assertEqualDiff(subst_dates(log), """\
668
631
    2 Lorem Ipsum\t2005-11-22 [merge]
669
 
      merge branch level1
 
632
      merge branch 1
670
633
      === modified file 'file2'
671
 
      --- file2\t2005-11-22 00:00:01 +0000
672
 
      +++ file2\t2005-11-22 00:00:02 +0000
 
634
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
635
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
673
636
      @@ -1,1 +1,1 @@
674
 
      -contents of level0/file2
 
637
      -contents of parent/file2
675
638
      +hello
676
639
 
677
640
    1 Lorem Ipsum\t2005-11-22
678
 
      in branch level0
 
641
      first post
679
642
      === added file 'file2'
680
 
      --- file2\t1970-01-01 00:00:00 +0000
681
 
      +++ file2\t2005-11-22 00:00:01 +0000
682
 
      @@ -0,0 +1,1 @@
683
 
      +contents of level0/file2
684
 
 
685
 
Use --include-merges or -n0 to see merged revisions.
686
 
"""
687
 
        self.check_log(expected, ['-p', '--short', 'file2'])
688
 
 
689
 
 
690
 
class TestLogUnicodeDiff(TestLog):
 
643
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
644
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
645
      @@ -0,0 +1,1 @@
 
646
      +contents of parent/file2
 
647
 
 
648
Use --levels 0 (or -n0) to see merged revisions.
 
649
""")
 
650
        out,err = self.run_bzr('log -p --short file1')
 
651
        self.assertEqual('', err)
 
652
        log = normalize_log(out)
 
653
        self.assertEqualDiff(subst_dates(log), """\
 
654
    1 Lorem Ipsum\t2005-11-22
 
655
      first post
 
656
      === added file 'file1'
 
657
      --- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
658
      +++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
659
      @@ -0,0 +1,1 @@
 
660
      +contents of parent/file1
 
661
 
 
662
""")
691
663
 
692
664
    def test_log_show_diff_non_ascii(self):
693
665
        # Smoke test for bug #328007 UnicodeDecodeError on 'log -p'
710
682
        self.assertEqual('', err)
711
683
 
712
684
 
713
 
class TestLogEncodings(tests.TestCaseInTempDir):
 
685
class TestLogEncodings(TestCaseInTempDir):
714
686
 
715
687
    _mu = u'\xb5'
716
688
    _message = u'Message with \xb5'
732
704
    ]
733
705
 
734
706
    def setUp(self):
735
 
        super(TestLogEncodings, self).setUp()
 
707
        TestCaseInTempDir.setUp(self)
736
708
        self.user_encoding = osutils._cached_user_encoding
737
 
        def restore():
738
 
            osutils._cached_user_encoding = self.user_encoding
739
 
        self.addCleanup(restore)
 
709
 
 
710
    def tearDown(self):
 
711
        osutils._cached_user_encoding = self.user_encoding
 
712
        TestCaseInTempDir.tearDown(self)
740
713
 
741
714
    def create_branch(self):
742
715
        bzr = self.run_bzr
810
783
        self.assertEquals(-1, stdout.find(test_in_cp1251))
811
784
 
812
785
 
813
 
class TestLogFile(tests.TestCaseWithTransport):
 
786
class TestLogFile(TestCaseWithTransport):
814
787
 
815
788
    def test_log_local_branch_file(self):
816
789
        """We should be able to log files in local treeless branches"""
1005
978
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
1006
979
 
1007
980
 
1008
 
class TestLogMultiple(tests.TestCaseWithTransport):
 
981
class TestLogMultiple(TestCaseWithTransport):
1009
982
 
1010
983
    def prepare_tree(self):
1011
984
        tree = self.make_branch_and_tree('parent')