~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

Merge cleanup into description

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
from itertools import izip
20
21
import os
21
22
import re
22
23
 
23
24
from bzrlib import (
 
25
    branchbuilder,
 
26
    log,
24
27
    osutils,
25
28
    tests,
26
29
    )
27
 
from bzrlib.tests import test_log
28
 
 
29
 
 
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
 
30
from bzrlib.tests import (
 
31
    script,
 
32
    test_log,
 
33
    )
 
34
 
 
35
 
 
36
class TestLog(tests.TestCaseWithTransport, test_log.TestLogMixin):
36
37
 
37
38
    def make_minimal_branch(self, path='.', format=None):
38
39
        tree = self.make_branch_and_tree(path, format=format)
63
64
        tree.commit(message='merge')
64
65
        return tree
65
66
 
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):
 
67
 
 
68
class TestLogWithLogCatcher(TestLog):
 
69
 
 
70
    def setUp(self):
 
71
        super(TestLogWithLogCatcher, self).setUp()
 
72
        # Capture log formatter creations
 
73
        class MyLogFormatter(test_log.LogCatcher):
 
74
 
 
75
            def __new__(klass, *args, **kwargs):
 
76
                self.log_catcher = test_log.LogCatcher(*args, **kwargs)
 
77
                # Always return our own log formatter
 
78
                return self.log_catcher
 
79
 
 
80
        def getme(branch):
 
81
                # Always return our own log formatter class hijacking the
 
82
                # default behavior (which requires setting up a config
 
83
                # variable)
 
84
            return MyLogFormatter
 
85
        self.overrideAttr(log.log_formatter_registry, 'get_default', getme)
 
86
 
 
87
    def get_captured_revisions(self):
 
88
        return self.log_catcher.revisions
 
89
 
 
90
    def assertLogRevnos(self, args, expected_revnos, working_dir='.'):
 
91
        self.run_bzr(['log'] + args, working_dir=working_dir)
 
92
        self.assertEqual(expected_revnos,
 
93
                         [r.revno for r in self.get_captured_revisions()])
 
94
 
 
95
    def assertLogRevnosAndDepths(self, args, expected_revnos_and_depths,
 
96
                                working_dir='.'):
 
97
        self.run_bzr(['log'] + args, working_dir=working_dir)
 
98
        self.assertEqual(expected_revnos_and_depths,
 
99
                         [(r.revno, r.merge_depth)
 
100
                           for r in self.get_captured_revisions()])
 
101
 
 
102
 
 
103
class TestLogRevSpecs(TestLogWithLogCatcher):
 
104
 
 
105
    def test_log_no_revspec(self):
 
106
        self.make_linear_branch()
 
107
        self.assertLogRevnos([], ['3', '2', '1'])
95
108
 
96
109
    def test_log_null_end_revspec(self):
97
110
        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)
105
 
 
106
 
        full_log = self.run_bzr(['log'])[0]
107
 
        log = self.run_bzr("log -r 1..")[0]
108
 
        self.assertEqualDiff(log, full_log)
 
111
        self.assertLogRevnos(['-r1..'], ['3', '2', '1'])
109
112
 
110
113
    def test_log_null_begin_revspec(self):
111
114
        self.make_linear_branch()
112
 
        full_log = self.run_bzr(['log'])[0]
113
 
        log = self.run_bzr("log -r ..3")[0]
114
 
        self.assertEqualDiff(full_log, log)
 
115
        self.assertLogRevnos(['-r..3'], ['3', '2', '1'])
115
116
 
116
117
    def test_log_null_both_revspecs(self):
117
118
        self.make_linear_branch()
118
 
        full_log = self.run_bzr(['log'])[0]
119
 
        log = self.run_bzr("log -r ..")[0]
120
 
        self.assertEqualDiff(full_log, log)
121
 
 
122
 
    def test_log_zero_revspec(self):
123
 
        self.make_minimal_branch()
124
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
125
 
                           ['log', '-r0'])
126
 
 
127
 
    def test_log_zero_begin_revspec(self):
128
 
        self.make_linear_branch()
129
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
130
 
                           ['log', '-r0..2'])
131
 
 
132
 
    def test_log_zero_end_revspec(self):
133
 
        self.make_linear_branch()
134
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
135
 
                           ['log', '-r-2..0'])
 
119
        self.assertLogRevnos(['-r..'], ['3', '2', '1'])
136
120
 
137
121
    def test_log_negative_begin_revspec_full_log(self):
138
122
        self.make_linear_branch()
139
 
        full_log = self.run_bzr(['log'])[0]
140
 
        log = self.run_bzr("log -r -3..")[0]
141
 
        self.assertEqualDiff(full_log, log)
 
123
        self.assertLogRevnos(['-r-3..'], ['3', '2', '1'])
142
124
 
143
125
    def test_log_negative_both_revspec_full_log(self):
144
126
        self.make_linear_branch()
145
 
        full_log = self.run_bzr(['log'])[0]
146
 
        log = self.run_bzr("log -r -3..-1")[0]
147
 
        self.assertEqualDiff(full_log, log)
 
127
        self.assertLogRevnos(['-r-3..-1'], ['3', '2', '1'])
148
128
 
149
129
    def test_log_negative_both_revspec_partial(self):
150
130
        self.make_linear_branch()
151
 
        log = self.run_bzr("log -r -3..-2")[0]
152
 
        self.assertTrue('revno: 1\n' in log)
153
 
        self.assertTrue('revno: 2\n' in log)
154
 
        self.assertTrue('revno: 3\n' not in log)
 
131
        self.assertLogRevnos(['-r-3..-2'], ['2', '1'])
155
132
 
156
133
    def test_log_negative_begin_revspec(self):
157
134
        self.make_linear_branch()
158
 
        log = self.run_bzr("log -r -2..")[0]
159
 
        self.assertTrue('revno: 1\n' not in log)
160
 
        self.assertTrue('revno: 2\n' in log)
161
 
        self.assertTrue('revno: 3\n' in log)
 
135
        self.assertLogRevnos(['-r-2..'], ['3', '2'])
162
136
 
163
137
    def test_log_positive_revspecs(self):
164
138
        self.make_linear_branch()
165
 
        full_log = self.run_bzr(['log'])[0]
166
 
        log = self.run_bzr("log -r 1..3")[0]
167
 
        self.assertEqualDiff(full_log, log)
 
139
        self.assertLogRevnos(['-r1..3'], ['3', '2', '1'])
168
140
 
169
141
    def test_log_dotted_revspecs(self):
170
142
        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))
173
 
 
174
 
    def test_log_reversed_revspecs(self):
175
 
        self.make_linear_branch()
176
 
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
177
 
                            'the end revision.\n',),
178
 
                           ['log', '-r3..1'])
179
 
 
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")
 
143
        self.assertLogRevnos(['-n0', '-r1..1.1.1'], ['1.1.1', '1'])
 
144
 
 
145
    def test_log_limit(self):
 
146
        tree = self.make_branch_and_tree('.')
 
147
        # We want more commits than our batch size starts at
 
148
        for pos in range(10):
 
149
            tree.commit("%s" % pos)
 
150
        self.assertLogRevnos(['--limit', '2'], ['10', '9'])
 
151
 
 
152
    def test_log_limit_short(self):
 
153
        self.make_linear_branch()
 
154
        self.assertLogRevnos(['-l', '2'], ['3', '2'])
 
155
 
 
156
    def test_log_change_revno(self):
 
157
        self.make_linear_branch()
 
158
        self.assertLogRevnos(['-c1'], ['1'])
 
159
 
 
160
 
 
161
class TestBug474807(TestLogWithLogCatcher):
 
162
 
 
163
    def setUp(self):
 
164
        super(TestBug474807, self).setUp()
 
165
        # FIXME: Using a MemoryTree would be even better here (but until we
 
166
        # stop calling run_bzr, there is no point) --vila 100118.
 
167
        builder = branchbuilder.BranchBuilder(self.get_transport())
 
168
        builder.start_series()
 
169
        # mainline
 
170
        builder.build_snapshot('1', None, [
 
171
            ('add', ('', 'root-id', 'directory', ''))])
 
172
        builder.build_snapshot('2', ['1'], [])
 
173
        # branch
 
174
        builder.build_snapshot('1.1.1', ['1'], [])
 
175
        # merge branch into mainline
 
176
        builder.build_snapshot('3', ['2', '1.1.1'], [])
 
177
        # new commits in branch
 
178
        builder.build_snapshot('1.1.2', ['1.1.1'], [])
 
179
        builder.build_snapshot('1.1.3', ['1.1.2'], [])
 
180
        # merge branch into mainline
 
181
        builder.build_snapshot('4', ['3', '1.1.3'], [])
 
182
        # merge mainline into branch
 
183
        builder.build_snapshot('1.1.4', ['1.1.3', '4'], [])
 
184
        # merge branch into mainline
 
185
        builder.build_snapshot('5', ['4', '1.1.4'], [])
 
186
        builder.finish_series()
 
187
 
 
188
    def test_n0(self):
 
189
        self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4'],
 
190
                             ['1.1.4', '4', '1.1.3', '1.1.2', '3', '1.1.1'])
 
191
    def test_n0_forward(self):
 
192
        self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4', '--forward'],
 
193
                             ['3', '1.1.1', '4', '1.1.2', '1.1.3', '1.1.4'])
 
194
 
 
195
    def test_n1(self):
 
196
        # starting from 1.1.4 we follow the left-hand ancestry
 
197
        self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4'],
 
198
                             ['1.1.4', '1.1.3', '1.1.2', '1.1.1'])
 
199
 
 
200
    def test_n1_forward(self):
 
201
        self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4', '--forward'],
 
202
                             ['1.1.1', '1.1.2', '1.1.3', '1.1.4'])
 
203
 
 
204
 
 
205
class TestLogRevSpecsWithPaths(TestLogWithLogCatcher):
 
206
 
 
207
    def test_log_revno_n_path_wrong_namespace(self):
 
208
        self.make_linear_branch('branch1')
 
209
        self.make_linear_branch('branch2')
 
210
        # There is no guarantee that a path exist between two arbitrary
 
211
        # revisions.
 
212
        self.run_bzr("log -r revno:2:branch1..revno:3:branch2", retcode=3)
 
213
        # But may be it's worth trying though ? -- vila 100115
 
214
 
 
215
    def test_log_revno_n_path_correct_order(self):
 
216
        self.make_linear_branch('branch2')
 
217
        self.assertLogRevnos(['-rrevno:1:branch2..revno:3:branch2'],
 
218
                             ['3', '2','1'])
185
219
 
186
220
    def test_log_revno_n_path(self):
187
 
        self.make_linear_branch('branch1')
188
221
        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
192
 
        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)
195
 
        log = self.run_bzr("log -r revno:1:branch2")[0]
196
 
        self.assertTrue('revno: 1\n' in log)
197
 
        self.assertTrue('revno: 2\n' not in log)
198
 
        self.assertTrue('branch nick: branch2\n' in log)
199
 
        self.assertTrue('branch nick: branch1\n' not in log)
 
222
        self.assertLogRevnos(['-rrevno:1:branch2'],
 
223
                             ['1'])
 
224
        rev_props = self.log_catcher.revisions[0].rev.properties
 
225
        self.assertEqual('branch2', rev_props['branch-nick'])
 
226
 
 
227
 
 
228
class TestLogErrors(TestLog):
 
229
 
 
230
    def test_log_zero_revspec(self):
 
231
        self.make_minimal_branch()
 
232
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
233
                           ['log', '-r0'])
 
234
 
 
235
    def test_log_zero_begin_revspec(self):
 
236
        self.make_linear_branch()
 
237
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
238
                           ['log', '-r0..2'])
 
239
 
 
240
    def test_log_zero_end_revspec(self):
 
241
        self.make_linear_branch()
 
242
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
243
                           ['log', '-r-2..0'])
200
244
 
201
245
    def test_log_nonexistent_revno(self):
202
246
        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'])
 
247
        self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
 
248
                            "does not exist in branch:"],
 
249
                           ['log', '-r1234'])
207
250
 
208
251
    def test_log_nonexistent_dotted_revno(self):
209
252
        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'])
214
 
 
215
 
    def test_log_change_revno(self):
216
 
        self.make_linear_branch()
217
 
        expected_log = self.run_bzr("log -r 1")[0]
218
 
        log = self.run_bzr("log -c 1")[0]
219
 
        self.assertEqualDiff(expected_log, log)
 
253
        self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
 
254
                            "does not exist in branch:"],
 
255
                           ['log',  '-r123.123'])
220
256
 
221
257
    def test_log_change_nonexistent_revno(self):
222
258
        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'])
 
259
        self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
 
260
                            "does not exist in branch:"],
 
261
                           ['log',  '-c1234'])
227
262
 
228
263
    def test_log_change_nonexistent_dotted_revno(self):
229
264
        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'])
 
265
        self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
 
266
                            "does not exist in branch:"],
 
267
                           ['log', '-c123.123'])
234
268
 
235
269
    def test_log_change_single_revno_only(self):
236
270
        self.make_minimal_branch()
252
286
                              'Path unknown at end or start of revision range: '
253
287
                              'does-not-exist')
254
288
 
 
289
    def test_log_reversed_revspecs(self):
 
290
        self.make_linear_branch()
 
291
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
 
292
                            'the end revision.\n',),
 
293
                           ['log', '-r3..1'])
 
294
 
 
295
    def test_log_reversed_dotted_revspecs(self):
 
296
        self.make_merged_branch()
 
297
        self.run_bzr_error(('bzr: ERROR: Start revision not found in '
 
298
                            'left-hand history of end revision.\n',),
 
299
                           "log -r 1.1.1..1")
 
300
 
 
301
    def test_log_bad_message_re(self):
 
302
        """Bad --message argument gives a sensible message
 
303
        
 
304
        See https://bugs.launchpad.net/bzr/+bug/251352
 
305
        """
 
306
        self.make_minimal_branch()
 
307
        out, err = self.run_bzr(['log', '-m', '*'], retcode=3)
 
308
        self.assertEqual("bzr: ERROR: Invalid regular expression"
 
309
            " in log message filter"
 
310
            ": '*'"
 
311
            ": nothing to repeat\n", err)
 
312
        self.assertEqual('', out)
 
313
 
 
314
    def test_log_unsupported_timezone(self):
 
315
        self.make_linear_branch()
 
316
        self.run_bzr_error(['bzr: ERROR: Unsupported timezone format "foo", '
 
317
                            'options are "utc", "original", "local".'],
 
318
                           ['log', '--timezone', 'foo'])
 
319
 
 
320
 
 
321
class TestLogTags(TestLog):
 
322
 
255
323
    def test_log_with_tags(self):
256
324
        tree = self.make_linear_branch(format='dirstate-tags')
257
325
        branch = tree.branch
282
350
        log = self.run_bzr("log -n0 -r3.1.1", working_dir='branch2')[0]
283
351
        self.assertContainsRe(log, r'tags: tag1')
284
352
 
285
 
    def test_log_limit(self):
286
 
        tree = self.make_branch_and_tree('.')
287
 
        # We want more commits than our batch size starts at
288
 
        for pos in range(10):
289
 
            tree.commit("%s" % pos)
290
 
        log = self.run_bzr("log --limit 2")[0]
291
 
        self.assertNotContainsRe(log, r'revno: 1\n')
292
 
        self.assertNotContainsRe(log, r'revno: 2\n')
293
 
        self.assertNotContainsRe(log, r'revno: 3\n')
294
 
        self.assertNotContainsRe(log, r'revno: 4\n')
295
 
        self.assertNotContainsRe(log, r'revno: 5\n')
296
 
        self.assertNotContainsRe(log, r'revno: 6\n')
297
 
        self.assertNotContainsRe(log, r'revno: 7\n')
298
 
        self.assertNotContainsRe(log, r'revno: 8\n')
299
 
        self.assertContainsRe(log, r'revno: 9\n')
300
 
        self.assertContainsRe(log, r'revno: 10\n')
301
 
 
302
 
    def test_log_limit_short(self):
303
 
        self.make_linear_branch()
304
 
        log = self.run_bzr("log -l 2")[0]
305
 
        self.assertNotContainsRe(log, r'revno: 1\n')
306
 
        self.assertContainsRe(log, r'revno: 2\n')
307
 
        self.assertContainsRe(log, r'revno: 3\n')
308
 
 
309
 
    def test_log_bad_message_re(self):
310
 
        """Bad --message argument gives a sensible message
311
 
        
312
 
        See https://bugs.launchpad.net/bzr/+bug/251352
313
 
        """
314
 
        self.make_minimal_branch()
315
 
        out, err = self.run_bzr(['log', '-m', '*'], retcode=3)
316
 
        self.assertEqual("bzr: ERROR: Invalid regular expression"
317
 
            " in log message filter"
318
 
            ": '*'"
319
 
            ": nothing to repeat\n", err)
320
 
        self.assertEqual('', out)
321
 
 
322
 
 
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
353
 
332
354
class TestLogVerbose(TestLog):
333
355
 
364
386
        self.assertUseLongDeltaFormat(['log', '--long', '-vv'])
365
387
 
366
388
 
367
 
class TestLogMerges(TestLog):
 
389
class TestLogMerges(TestLogWithLogCatcher):
368
390
 
369
391
    def setUp(self):
370
392
        super(TestLogMerges, self).setUp()
372
394
 
373
395
    def make_branches_with_merges(self):
374
396
        level0 = self.make_branch_and_tree('level0')
375
 
        level0.commit(message='in branch level0', **self.commit_options())
376
 
 
 
397
        self.wt_commit(level0, 'in branch level0')
377
398
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
378
 
        level1.commit(message='in branch level1', **self.commit_options())
379
 
 
 
399
        self.wt_commit(level1, 'in branch level1')
380
400
        level2 = level1.bzrdir.sprout('level2').open_workingtree()
381
 
        level2.commit(message='in branch level2', **self.commit_options())
382
 
 
 
401
        self.wt_commit(level2, 'in branch level2')
383
402
        level1.merge_from_branch(level2.branch)
384
 
        level1.commit(message='merge branch level2', **self.commit_options())
385
 
 
 
403
        self.wt_commit(level1, 'merge branch level2')
386
404
        level0.merge_from_branch(level1.branch)
387
 
        level0.commit(message='merge branch level1', **self.commit_options())
 
405
        self.wt_commit(level0, 'merge branch level1')
388
406
 
389
407
    def test_merges_are_indented_by_level(self):
390
 
        expected = """\
391
 
------------------------------------------------------------
392
 
revno: 2 [merge]
393
 
committer: Lorem Ipsum <test@example.com>
394
 
branch nick: level0
395
 
timestamp: Just now
396
 
message:
397
 
  merge branch level1
398
 
    ------------------------------------------------------------
399
 
    revno: 1.1.2 [merge]
400
 
    committer: Lorem Ipsum <test@example.com>
401
 
    branch nick: level1
402
 
    timestamp: Just now
403
 
    message:
404
 
      merge branch level2
405
 
        ------------------------------------------------------------
406
 
        revno: 1.2.1
407
 
        committer: Lorem Ipsum <test@example.com>
408
 
        branch nick: level2
409
 
        timestamp: Just now
410
 
        message:
411
 
          in branch level2
412
 
    ------------------------------------------------------------
413
 
    revno: 1.1.1
414
 
    committer: Lorem Ipsum <test@example.com>
415
 
    branch nick: level1
416
 
    timestamp: Just now
417
 
    message:
418
 
      in branch level1
419
 
------------------------------------------------------------
420
 
revno: 1
421
 
committer: Lorem Ipsum <test@example.com>
422
 
branch nick: level0
423
 
timestamp: Just now
424
 
message:
425
 
  in branch level0
426
 
"""
427
 
        self.check_log(expected, ['-n0'])
 
408
        self.run_bzr(['log', '-n0'], working_dir='level0')
 
409
        revnos_and_depth = [(r.revno, r.merge_depth)
 
410
                            for r in self.get_captured_revisions()]
 
411
        self.assertEqual([('2', 0), ('1.1.2', 1), ('1.2.1', 2), ('1.1.1', 1),
 
412
                          ('1', 0)],
 
413
                         [(r.revno, r.merge_depth)
 
414
                            for r in self.get_captured_revisions()])
428
415
 
429
416
    def test_force_merge_revisions_off(self):
430
 
        expected = """\
431
 
------------------------------------------------------------
432
 
revno: 2 [merge]
433
 
committer: Lorem Ipsum <test@example.com>
434
 
branch nick: level0
435
 
timestamp: Just now
436
 
message:
437
 
  merge branch level1
438
 
------------------------------------------------------------
439
 
revno: 1
440
 
committer: Lorem Ipsum <test@example.com>
441
 
branch nick: level0
442
 
timestamp: Just now
443
 
message:
444
 
  in branch level0
445
 
"""
446
 
        self.check_log(expected, ['--long', '-n1'])
 
417
        self.assertLogRevnos(['-n1'], ['2', '1'], working_dir='level0')
447
418
 
448
419
    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'])
 
420
        self.assertLogRevnos(['-n0'], ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
 
421
                             working_dir='level0')
467
422
 
468
423
    def test_include_merges(self):
469
424
        # Confirm --include-merges gives the same output as -n0
 
425
        self.assertLogRevnos(['--include-merges'],
 
426
                             ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
 
427
                             working_dir='level0')
 
428
        self.assertLogRevnos(['--include-merges'],
 
429
                             ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
 
430
                             working_dir='level0')
470
431
        out_im, err_im = self.run_bzr('log --include-merges',
471
432
                                      working_dir='level0')
472
433
        out_n0, err_n0 = self.run_bzr('log -n0', working_dir='level0')
475
436
        self.assertEqual(out_im, out_n0)
476
437
 
477
438
    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'])
 
439
        self.assertLogRevnos(['-n2'],
 
440
                             ['2', '1.1.2', '1.1.1', '1'],
 
441
                             working_dir='level0')
493
442
 
494
443
    def test_merges_single_merge_rev(self):
495
 
        expected = """\
496
 
------------------------------------------------------------
497
 
revno: 1.1.2 [merge]
498
 
committer: Lorem Ipsum <test@example.com>
499
 
branch nick: level1
500
 
timestamp: Just now
501
 
message:
502
 
  merge branch level2
503
 
    ------------------------------------------------------------
504
 
    revno: 1.2.1
505
 
    committer: Lorem Ipsum <test@example.com>
506
 
    branch nick: level2
507
 
    timestamp: Just now
508
 
    message:
509
 
      in branch level2
510
 
"""
511
 
        self.check_log(expected, ['-n0', '-r1.1.2'])
 
444
        self.assertLogRevnosAndDepths(['-n0', '-r1.1.2'],
 
445
                                      [('1.1.2', 0), ('1.2.1', 1)],
 
446
                                      working_dir='level0')
512
447
 
513
448
    def test_merges_partial_range(self):
514
 
        expected = """\
515
 
------------------------------------------------------------
516
 
revno: 1.1.2 [merge]
517
 
committer: Lorem Ipsum <test@example.com>
518
 
branch nick: level1
519
 
timestamp: Just now
520
 
message:
521
 
  merge branch level2
522
 
    ------------------------------------------------------------
523
 
    revno: 1.2.1
524
 
    committer: Lorem Ipsum <test@example.com>
525
 
    branch nick: level2
526
 
    timestamp: Just now
527
 
    message:
528
 
      in branch level2
529
 
------------------------------------------------------------
530
 
revno: 1.1.1
531
 
committer: Lorem Ipsum <test@example.com>
532
 
branch nick: level1
533
 
timestamp: Just now
534
 
message:
535
 
  in branch level1
536
 
"""
537
 
        self.check_log(expected, ['-n0', '-r1.1.1..1.1.2'])
 
449
        self.assertLogRevnosAndDepths(
 
450
                ['-n0', '-r1.1.1..1.1.2'],
 
451
                [('1.1.2', 0), ('1.2.1', 1), ('1.1.1', 0)],
 
452
                working_dir='level0')
538
453
 
539
454
    def test_merges_partial_range_ignore_before_lower_bound(self):
540
455
        """Dont show revisions before the lower bound's merged revs"""
541
 
        expected = """\
542
 
    2 Lorem Ipsum\t2005-11-22 [merge]
543
 
      merge branch level1
544
 
 
545
 
          1.1.2 Lorem Ipsum\t2005-11-22 [merge]
546
 
                merge branch level2
547
 
 
548
 
              1.2.1 Lorem Ipsum\t2005-11-22
549
 
                    in branch level2
550
 
 
551
 
"""
552
 
        self.check_log(expected, ['--short', '-n0', '-r1.1.2..2'])
553
 
 
554
 
 
555
 
class TestLogDiff(TestLog):
 
456
        self.assertLogRevnosAndDepths(
 
457
                ['-n0', '-r1.1.2..2'],
 
458
                [('2', 0), ('1.1.2', 1), ('1.2.1', 2)],
 
459
                working_dir='level0')
 
460
 
 
461
 
 
462
class TestLogDiff(TestLogWithLogCatcher):
 
463
 
 
464
    # FIXME: We need specific tests for each LogFormatter about how the diffs
 
465
    # are displayed: --long indent them by depth, --short use a fixed
 
466
    # indent and --line does't display them. -- vila 10019
556
467
 
557
468
    def setUp(self):
558
469
        super(TestLogDiff, self).setUp()
563
474
        self.build_tree(['level0/file1', 'level0/file2'])
564
475
        level0.add('file1')
565
476
        level0.add('file2')
566
 
        level0.commit(message='in branch level0', **self.commit_options())
 
477
        self.wt_commit(level0, 'in branch level0')
567
478
 
568
479
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
569
480
        self.build_tree_contents([('level1/file2', 'hello\n')])
570
 
        level1.commit(message='in branch level1', **self.commit_options())
 
481
        self.wt_commit(level1, 'in branch level1')
571
482
        level0.merge_from_branch(level1.branch)
572
 
        level0.commit(message='merge branch level1', **self.commit_options())
 
483
        self.wt_commit(level0, 'merge branch level1')
573
484
 
574
 
    def test_log_show_diff_long_with_merges(self):
575
 
        out,err = self.run_bzr('log -p -n0')
576
 
        self.assertEqual('', err)
577
 
        log = test_log.normalize_log(out)
578
 
        expected = """\
579
 
------------------------------------------------------------
580
 
revno: 2 [merge]
581
 
committer: Lorem Ipsum <test@example.com>
582
 
branch nick: level0
583
 
timestamp: Just now
584
 
message:
585
 
  merge branch level1
586
 
diff:
587
 
=== modified file 'file2'
588
 
--- file2\t2005-11-22 00:00:01 +0000
589
 
+++ file2\t2005-11-22 00:00:02 +0000
590
 
@@ -1,1 +1,1 @@
591
 
-contents of level0/file2
592
 
+hello
593
 
    ------------------------------------------------------------
594
 
    revno: 1.1.1
595
 
    committer: Lorem Ipsum <test@example.com>
596
 
    branch nick: level1
597
 
    timestamp: Just now
598
 
    message:
599
 
      in branch level1
600
 
    diff:
601
 
    === modified file 'file2'
602
 
    --- file2\t2005-11-22 00:00:01 +0000
603
 
    +++ file2\t2005-11-22 00:00:02 +0000
604
 
    @@ -1,1 +1,1 @@
605
 
    -contents of level0/file2
606
 
    +hello
607
 
------------------------------------------------------------
608
 
revno: 1
609
 
committer: Lorem Ipsum <test@example.com>
610
 
branch nick: level0
611
 
timestamp: Just now
612
 
message:
613
 
  in branch level0
614
 
diff:
615
 
=== added file 'file1'
 
485
    def _diff_file1_revno1(self):
 
486
        return """=== added file 'file1'
616
487
--- file1\t1970-01-01 00:00:00 +0000
617
 
+++ file1\t2005-11-22 00:00:01 +0000
 
488
+++ file1\t2005-11-22 00:00:00 +0000
618
489
@@ -0,0 +1,1 @@
619
490
+contents of level0/file1
620
491
 
621
 
=== added file 'file2'
 
492
"""
 
493
 
 
494
    def _diff_file2_revno2(self):
 
495
        return """=== modified file 'file2'
 
496
--- file2\t2005-11-22 00:00:00 +0000
 
497
+++ file2\t2005-11-22 00:00:01 +0000
 
498
@@ -1,1 +1,1 @@
 
499
-contents of level0/file2
 
500
+hello
 
501
 
 
502
"""
 
503
 
 
504
    def _diff_file2_revno1_1_1(self):
 
505
        return """=== modified file 'file2'
 
506
--- file2\t2005-11-22 00:00:00 +0000
 
507
+++ file2\t2005-11-22 00:00:01 +0000
 
508
@@ -1,1 +1,1 @@
 
509
-contents of level0/file2
 
510
+hello
 
511
 
 
512
"""
 
513
 
 
514
    def _diff_file2_revno1(self):
 
515
        return """=== added file 'file2'
622
516
--- file2\t1970-01-01 00:00:00 +0000
623
 
+++ file2\t2005-11-22 00:00:01 +0000
 
517
+++ file2\t2005-11-22 00:00:00 +0000
624
518
@@ -0,0 +1,1 @@
625
519
+contents of level0/file2
626
 
"""
627
 
        self.check_log(expected, ['-p', '-n0'])
628
 
 
629
 
    def test_log_show_diff_short(self):
630
 
        expected = """\
631
 
    2 Lorem Ipsum\t2005-11-22 [merge]
632
 
      merge branch level1
633
 
      === modified file 'file2'
634
 
      --- file2\t2005-11-22 00:00:01 +0000
635
 
      +++ file2\t2005-11-22 00:00:02 +0000
636
 
      @@ -1,1 +1,1 @@
637
 
      -contents of level0/file2
638
 
      +hello
639
 
 
640
 
    1 Lorem Ipsum\t2005-11-22
641
 
      in branch level0
642
 
      === added file 'file1'
643
 
      --- file1\t1970-01-01 00:00:00 +0000
644
 
      +++ file1\t2005-11-22 00:00:01 +0000
645
 
      @@ -0,0 +1,1 @@
646
 
      +contents of level0/file1
647
 
\x20\x20\x20\x20\x20\x20
648
 
      === added file 'file2'
649
 
      --- file2\t1970-01-01 00:00:00 +0000
650
 
      +++ file2\t2005-11-22 00:00:01 +0000
651
 
      @@ -0,0 +1,1 @@
652
 
      +contents of level0/file2
653
 
 
654
 
Use --include-merges or -n0 to see merged revisions.
655
 
"""
656
 
        self.check_log(expected, ['-p', '--short'])
657
 
 
658
 
    def test_log_show_diff_line(self):
659
 
        # Not supported by this formatter so expect plain output
660
 
        expected = """\
661
 
2: Lorem Ipsum 2005-11-22 [merge] merge branch level1
662
 
1: Lorem Ipsum 2005-11-22 in branch level0
663
 
"""
664
 
        self.check_log(expected, ['-p', '--line'])
665
 
 
666
 
    def test_log_show_diff_file1(self):
667
 
        """Only the diffs for the given file are to be shown"""
668
 
        expected = """\
669
 
    1 Lorem Ipsum\t2005-11-22
670
 
      in branch level0
671
 
      === added file 'file1'
672
 
      --- file1\t1970-01-01 00:00:00 +0000
673
 
      +++ file1\t2005-11-22 00:00:01 +0000
674
 
      @@ -0,0 +1,1 @@
675
 
      +contents of level0/file1
676
 
 
677
 
"""
678
 
        self.check_log(expected, ['-p', '--short', 'file1'])
679
 
 
680
 
    def test_log_show_diff_file2(self):
681
 
        """Only the diffs for the given file are to be shown"""
682
 
        expected = """\
683
 
    2 Lorem Ipsum\t2005-11-22 [merge]
684
 
      merge branch level1
685
 
      === modified file 'file2'
686
 
      --- file2\t2005-11-22 00:00:01 +0000
687
 
      +++ file2\t2005-11-22 00:00:02 +0000
688
 
      @@ -1,1 +1,1 @@
689
 
      -contents of level0/file2
690
 
      +hello
691
 
 
692
 
    1 Lorem Ipsum\t2005-11-22
693
 
      in branch level0
694
 
      === added file 'file2'
695
 
      --- file2\t1970-01-01 00:00:00 +0000
696
 
      +++ file2\t2005-11-22 00:00:01 +0000
697
 
      @@ -0,0 +1,1 @@
698
 
      +contents of level0/file2
699
 
 
700
 
Use --include-merges or -n0 to see merged revisions.
701
 
"""
702
 
        self.check_log(expected, ['-p', '--short', 'file2'])
 
520
 
 
521
"""
 
522
 
 
523
    def assertLogRevnosAndDiff(self, args, expected,
 
524
                            working_dir='.'):
 
525
        self.run_bzr(['log', '-p'] + args, working_dir=working_dir)
 
526
        expected_revnos_and_depths = [
 
527
            (revno, depth) for revno, depth, diff in expected]
 
528
        # Check the revnos and depths first to make debugging easier
 
529
        self.assertEqual(expected_revnos_and_depths,
 
530
                         [(r.revno, r.merge_depth)
 
531
                           for r in self.get_captured_revisions()])
 
532
        # Now check the diffs, adding the revno  in case of failure
 
533
        fmt = 'In revno %s\n%s'
 
534
        for expected_rev, actual_rev in izip(expected,
 
535
                                             self.get_captured_revisions()):
 
536
            revno, depth, expected_diff = expected_rev
 
537
            actual_diff = actual_rev.diff
 
538
            self.assertEqualDiff(fmt % (revno, expected_diff),
 
539
                                 fmt % (revno, actual_diff))
 
540
 
 
541
    def test_log_diff_with_merges(self):
 
542
        self.assertLogRevnosAndDiff(
 
543
            ['-n0'],
 
544
            [('2', 0, self._diff_file2_revno2()),
 
545
             ('1.1.1', 1, self._diff_file2_revno1_1_1()),
 
546
             ('1', 0, self._diff_file1_revno1()
 
547
              + self._diff_file2_revno1())],
 
548
            working_dir='level0')
 
549
 
 
550
 
 
551
    def test_log_diff_file1(self):
 
552
        self.assertLogRevnosAndDiff(['-n0', 'file1'],
 
553
                                    [('1', 0, self._diff_file1_revno1())],
 
554
                                    working_dir='level0')
 
555
 
 
556
    def test_log_diff_file2(self):
 
557
        self.assertLogRevnosAndDiff(['-n1', 'file2'],
 
558
                                    [('2', 0, self._diff_file2_revno2()),
 
559
                                     ('1', 0, self._diff_file2_revno1())],
 
560
                                    working_dir='level0')
703
561
 
704
562
 
705
563
class TestLogUnicodeDiff(TestLog):
748
606
 
749
607
    def setUp(self):
750
608
        super(TestLogEncodings, self).setUp()
751
 
        self.user_encoding = osutils._cached_user_encoding
752
 
        def restore():
753
 
            osutils._cached_user_encoding = self.user_encoding
754
 
        self.addCleanup(restore)
 
609
        self.overrideAttr(osutils, '_cached_user_encoding')
755
610
 
756
611
    def create_branch(self):
757
612
        bzr = self.run_bzr
758
613
        bzr('init')
759
 
        open('a', 'wb').write('some stuff\n')
 
614
        self.build_tree_contents([('a', 'some stuff\n')])
760
615
        bzr('add a')
761
616
        bzr(['commit', '-m', self._message])
762
617
 
825
680
        self.assertEquals(-1, stdout.find(test_in_cp1251))
826
681
 
827
682
 
828
 
class TestLogFile(tests.TestCaseWithTransport):
 
683
class TestLogFile(TestLogWithLogCatcher):
829
684
 
830
685
    def test_log_local_branch_file(self):
831
686
        """We should be able to log files in local treeless branches"""
860
715
            tree.commit('remove file1')
861
716
        os.chdir('parent')
862
717
 
863
 
    def test_log_file(self):
864
 
        """The log for a particular file should only list revs for that file"""
865
 
        self.prepare_tree()
866
 
        log = self.run_bzr('log -n0 file1')[0]
867
 
        self.assertContainsRe(log, 'revno: 1\n')
868
 
        self.assertNotContainsRe(log, 'revno: 2\n')
869
 
        self.assertNotContainsRe(log, 'revno: 3\n')
870
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
871
 
        self.assertNotContainsRe(log, 'revno: 4 ')
872
 
        log = self.run_bzr('log -n0 file2')[0]
873
 
        self.assertNotContainsRe(log, 'revno: 1\n')
874
 
        self.assertContainsRe(log, 'revno: 2\n')
875
 
        self.assertNotContainsRe(log, 'revno: 3\n')
876
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
877
 
        self.assertContainsRe(log, 'revno: 4 ')
878
 
        log = self.run_bzr('log -n0 file3')[0]
879
 
        self.assertNotContainsRe(log, 'revno: 1\n')
880
 
        self.assertNotContainsRe(log, 'revno: 2\n')
881
 
        self.assertContainsRe(log, 'revno: 3\n')
882
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
883
 
        self.assertNotContainsRe(log, 'revno: 4 ')
884
 
        log = self.run_bzr('log -n0 -r3.1.1 file2')[0]
885
 
        self.assertNotContainsRe(log, 'revno: 1\n')
886
 
        self.assertNotContainsRe(log, 'revno: 2\n')
887
 
        self.assertNotContainsRe(log, 'revno: 3\n')
888
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
889
 
        self.assertNotContainsRe(log, 'revno: 4 ')
890
 
        log = self.run_bzr('log -n0 -r4 file2')[0]
891
 
        self.assertNotContainsRe(log, 'revno: 1\n')
892
 
        self.assertNotContainsRe(log, 'revno: 2\n')
893
 
        self.assertNotContainsRe(log, 'revno: 3\n')
894
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
895
 
        self.assertContainsRe(log, 'revno: 4 ')
896
 
        log = self.run_bzr('log -n0 -r3.. file2')[0]
897
 
        self.assertNotContainsRe(log, 'revno: 1\n')
898
 
        self.assertNotContainsRe(log, 'revno: 2\n')
899
 
        self.assertNotContainsRe(log, 'revno: 3\n')
900
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
901
 
        self.assertContainsRe(log, 'revno: 4 ')
902
 
        log = self.run_bzr('log -n0 -r..3 file2')[0]
903
 
        self.assertNotContainsRe(log, 'revno: 1\n')
904
 
        self.assertContainsRe(log, 'revno: 2\n')
905
 
        self.assertNotContainsRe(log, 'revno: 3\n')
906
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
907
 
        self.assertNotContainsRe(log, 'revno: 4 ')
 
718
    # FIXME: It would be good to parametrize the following tests against all
 
719
    # formatters. But the revisions selection is not *currently* part of the
 
720
    # LogFormatter contract, so using LogCatcher is sufficient -- vila 100118
 
721
    def test_log_file1(self):
 
722
        self.prepare_tree()
 
723
        self.assertLogRevnos(['-n0', 'file1'], ['1'])
 
724
 
 
725
    def test_log_file2(self):
 
726
        self.prepare_tree()
 
727
        # file2 full history
 
728
        self.assertLogRevnos(['-n0', 'file2'], ['4', '3.1.1', '2'])
 
729
        # file2 in a merge revision
 
730
        self.assertLogRevnos(['-n0', '-r3.1.1', 'file2'], ['3.1.1'])
 
731
        # file2 in a mainline revision
 
732
        self.assertLogRevnos(['-n0', '-r4', 'file2'], ['4', '3.1.1'])
 
733
        # file2 since a revision
 
734
        self.assertLogRevnos(['-n0', '-r3..', 'file2'], ['4', '3.1.1'])
 
735
        # file2 up to a revision
 
736
        self.assertLogRevnos(['-n0', '-r..3', 'file2'], ['2'])
 
737
 
 
738
    def test_log_file3(self):
 
739
        self.prepare_tree()
 
740
        self.assertLogRevnos(['-n0', 'file3'], ['3'])
908
741
 
909
742
    def test_log_file_historical_missing(self):
910
743
        # Check logging a deleted file gives an error if the
918
751
        # Check logging a deleted file is ok if the file existed
919
752
        # at the end the revision range
920
753
        self.prepare_tree(complex=True)
921
 
        log, err = self.run_bzr('log -n0 -r..4 file2')
922
 
        self.assertEquals('', err)
923
 
        self.assertNotContainsRe(log, 'revno: 1\n')
924
 
        self.assertContainsRe(log, 'revno: 2\n')
925
 
        self.assertNotContainsRe(log, 'revno: 3\n')
926
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
927
 
        self.assertContainsRe(log, 'revno: 4 ')
 
754
        self.assertLogRevnos(['-n0', '-r..4', 'file2'], ['4', '3.1.1', '2'])
928
755
 
929
756
    def test_log_file_historical_start(self):
930
757
        # Check logging a deleted file is ok if the file existed
931
758
        # at the start of the revision range
932
759
        self.prepare_tree(complex=True)
933
 
        log, err = self.run_bzr('log file1')
934
 
        self.assertEquals('', err)
935
 
        self.assertContainsRe(log, 'revno: 1\n')
936
 
        self.assertNotContainsRe(log, 'revno: 2\n')
937
 
        self.assertNotContainsRe(log, 'revno: 3\n')
938
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
939
 
        self.assertNotContainsRe(log, 'revno: 4 ')
 
760
        self.assertLogRevnos(['file1'], ['1'])
940
761
 
941
762
    def test_log_file_renamed(self):
942
763
        """File matched against revision range, not current tree."""
948
769
        self.assertContainsRe(err, err_msg)
949
770
 
950
771
        # Check we can see a renamed file if we give the right end revision
951
 
        log, err = self.run_bzr('log -r..4 file3')
952
 
        self.assertEquals('', err)
953
 
        self.assertNotContainsRe(log, 'revno: 1\n')
954
 
        self.assertNotContainsRe(log, 'revno: 2\n')
955
 
        self.assertContainsRe(log, 'revno: 3\n')
956
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
957
 
        self.assertNotContainsRe(log, 'revno: 4 ')
958
 
 
959
 
    def test_line_log_file(self):
960
 
        """The line log for a file should only list relevant mainline revs"""
961
 
        # Note: this also implicitly  covers the short logging case.
962
 
        # We test using --line in preference to --short because matching
963
 
        # revnos in the output of --line is more reliable.
964
 
        self.prepare_tree()
965
 
 
966
 
        # full history of file1
967
 
        log = self.run_bzr('log --line file1')[0]
968
 
        self.assertContainsRe(log, '^1:', re.MULTILINE)
969
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
970
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
971
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
972
 
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
973
 
 
974
 
        # full history of file2
975
 
        log = self.run_bzr('log --line file2')[0]
976
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
977
 
        self.assertContainsRe(log, '^2:', re.MULTILINE)
978
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
979
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
980
 
        self.assertContainsRe(log, '^4:', re.MULTILINE)
981
 
 
982
 
        # full history of file3
983
 
        log = self.run_bzr('log --line file3')[0]
984
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
985
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
986
 
        self.assertContainsRe(log, '^3:', re.MULTILINE)
987
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
988
 
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
989
 
 
990
 
        # file in a merge revision
991
 
        log = self.run_bzr('log --line -r3.1.1 file2')[0]
992
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
993
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
994
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
995
 
        self.assertContainsRe(log, '^3.1.1:', re.MULTILINE)
996
 
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
997
 
 
998
 
        # file in a mainline revision
999
 
        log = self.run_bzr('log --line -r4 file2')[0]
1000
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
1001
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
1002
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
1003
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
1004
 
        self.assertContainsRe(log, '^4:', re.MULTILINE)
1005
 
 
1006
 
        # file since a revision
1007
 
        log = self.run_bzr('log --line -r3.. file2')[0]
1008
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
1009
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
1010
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
1011
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
1012
 
        self.assertContainsRe(log, '^4:', re.MULTILINE)
1013
 
 
1014
 
        # file up to a revision
1015
 
        log = self.run_bzr('log --line -r..3 file2')[0]
1016
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
1017
 
        self.assertContainsRe(log, '^2:', re.MULTILINE)
1018
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
1019
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
1020
 
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
1021
 
 
1022
 
 
1023
 
class TestLogMultiple(tests.TestCaseWithTransport):
 
772
        self.assertLogRevnos(['-r..4', 'file3'], ['3'])
 
773
 
 
774
 
 
775
class TestLogMultiple(TestLogWithLogCatcher):
1024
776
 
1025
777
    def prepare_tree(self):
1026
778
        tree = self.make_branch_and_tree('parent')
1049
801
        tree.commit(message='merge child branch')
1050
802
        os.chdir('parent')
1051
803
 
1052
 
    def assertRevnos(self, paths_str, expected_revnos):
1053
 
        # confirm the revision numbers in log --line output are those expected
1054
 
        out, err = self.run_bzr('log --line -n0 %s' % (paths_str,))
1055
 
        self.assertEqual('', err)
1056
 
        revnos = [s.split(':', 1)[0].lstrip() for s in out.splitlines()]
1057
 
        self.assertEqual(expected_revnos, revnos)
1058
 
 
1059
804
    def test_log_files(self):
1060
805
        """The log for multiple file should only list revs for those files"""
1061
806
        self.prepare_tree()
1062
 
        self.assertRevnos('file1 file2 dir1/dir2/file3',
1063
 
            ['6', '5.1.1', '3', '2', '1'])
 
807
        self.assertLogRevnos(['file1', 'file2', 'dir1/dir2/file3'],
 
808
                             ['6', '5.1.1', '3', '2', '1'])
1064
809
 
1065
810
    def test_log_directory(self):
1066
811
        """The log for a directory should show all nested files."""
1067
812
        self.prepare_tree()
1068
 
        self.assertRevnos('dir1', ['5', '3'])
 
813
        self.assertLogRevnos(['dir1'], ['5', '3'])
1069
814
 
1070
815
    def test_log_nested_directory(self):
1071
816
        """The log for a directory should show all nested files."""
1072
817
        self.prepare_tree()
1073
 
        self.assertRevnos('dir1/dir2', ['3'])
 
818
        self.assertLogRevnos(['dir1/dir2'], ['3'])
1074
819
 
1075
820
    def test_log_in_nested_directory(self):
1076
821
        """The log for a directory should show all nested files."""
1077
822
        self.prepare_tree()
1078
823
        os.chdir("dir1")
1079
 
        self.assertRevnos('.', ['5', '3'])
 
824
        self.assertLogRevnos(['.'], ['5', '3'])
1080
825
 
1081
826
    def test_log_files_and_directories(self):
1082
827
        """Logging files and directories together should be fine."""
1083
828
        self.prepare_tree()
1084
 
        self.assertRevnos('file4 dir1/dir2', ['4', '3'])
 
829
        self.assertLogRevnos(['file4', 'dir1/dir2'], ['4', '3'])
1085
830
 
1086
831
    def test_log_files_and_dirs_in_nested_directory(self):
1087
832
        """The log for a directory should show all nested files."""
1088
833
        self.prepare_tree()
1089
834
        os.chdir("dir1")
1090
 
        self.assertRevnos('dir2 file5', ['5', '3'])
 
835
        self.assertLogRevnos(['dir2', 'file5'], ['5', '3'])