1
# Copyright (C) 2006-2010 Canonical Ltd
1
# Copyright (C) 2005 by Canonical Ltd
2
# -*- coding: utf-8 -*-
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
5
6
# the Free Software Foundation; either version 2 of the License, or
6
7
# (at your option) any later version.
8
9
# This program is distributed in the hope that it will be useful,
9
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
12
# GNU General Public License for more details.
13
14
# You should have received a copy of the GNU General Public License
14
15
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19
"""Black-box tests for bzr log."""
20
from itertools import izip
31
from bzrlib.tests import (
37
class TestLog(tests.TestCaseWithTransport, test_log.TestLogMixin):
39
def make_minimal_branch(self, path='.', format=None):
40
tree = self.make_branch_and_tree(path, format=format)
41
self.build_tree([path + '/hello.txt'])
43
tree.commit(message='message1')
46
def make_linear_branch(self, path='.', format=None):
47
tree = self.make_branch_and_tree(path, format=format)
49
[path + '/hello.txt', path + '/goodbye.txt', path + '/meep.txt'])
51
tree.commit(message='message1')
52
tree.add('goodbye.txt')
53
tree.commit(message='message2')
55
tree.commit(message='message3')
58
def make_merged_branch(self, path='.', format=None):
59
tree = self.make_linear_branch(path, format)
60
tree2 = tree.bzrdir.sprout('tree2',
61
revision_id=tree.branch.get_rev_id(1)).open_workingtree()
62
tree2.commit(message='tree2 message2')
63
tree2.commit(message='tree2 message3')
64
tree.merge_from_branch(tree2.branch)
65
tree.commit(message='merge')
69
class TestLogWithLogCatcher(TestLog):
72
super(TestLogWithLogCatcher, self).setUp()
73
# Capture log formatter creations
74
class MyLogFormatter(test_log.LogCatcher):
76
def __new__(klass, *args, **kwargs):
77
self.log_catcher = test_log.LogCatcher(*args, **kwargs)
78
# Always return our own log formatter
79
return self.log_catcher
82
# Always return our own log formatter class hijacking the
83
# default behavior (which requires setting up a config
86
self.overrideAttr(log.log_formatter_registry, 'get_default', getme)
88
def get_captured_revisions(self):
89
return self.log_catcher.revisions
91
def assertLogRevnos(self, args, expected_revnos, working_dir='.'):
92
self.run_bzr(['log'] + args, working_dir=working_dir)
93
self.assertEqual(expected_revnos,
94
[r.revno for r in self.get_captured_revisions()])
96
def assertLogRevnosAndDepths(self, args, expected_revnos_and_depths,
98
self.run_bzr(['log'] + args, working_dir=working_dir)
99
self.assertEqual(expected_revnos_and_depths,
100
[(r.revno, r.merge_depth)
101
for r in self.get_captured_revisions()])
104
class TestLogRevSpecs(TestLogWithLogCatcher):
106
def test_log_no_revspec(self):
107
self.make_linear_branch()
108
self.assertLogRevnos([], ['3', '2', '1'])
24
from bzrlib.tests.blackbox import ExternalBase
25
from bzrlib.tests import TestCaseInTempDir
28
class TestLog(ExternalBase):
32
self.build_tree(['hello.txt', 'goodbye.txt', 'meep.txt'])
33
self.runbzr("add hello.txt")
34
self.runbzr("commit -m message1 hello.txt")
35
self.runbzr("add goodbye.txt")
36
self.runbzr("commit -m message2 goodbye.txt")
37
self.runbzr("add meep.txt")
38
self.runbzr("commit -m message3 meep.txt")
39
self.full_log = self.runbzr("log")[0]
110
41
def test_log_null_end_revspec(self):
111
self.make_linear_branch()
112
self.assertLogRevnos(['-r1..'], ['3', '2', '1'])
43
self.assertTrue('revno: 1\n' in self.full_log)
44
self.assertTrue('revno: 2\n' in self.full_log)
45
self.assertTrue('revno: 3\n' in self.full_log)
46
self.assertTrue('message:\n message1\n' in self.full_log)
47
self.assertTrue('message:\n message2\n' in self.full_log)
48
self.assertTrue('message:\n message3\n' in self.full_log)
50
log = self.runbzr("log -r 1..")[0]
51
self.assertEquals(log, self.full_log)
114
53
def test_log_null_begin_revspec(self):
115
self.make_linear_branch()
116
self.assertLogRevnos(['-r..3'], ['3', '2', '1'])
55
log = self.runbzr("log -r ..3")[0]
56
self.assertEquals(self.full_log, log)
118
58
def test_log_null_both_revspecs(self):
119
self.make_linear_branch()
120
self.assertLogRevnos(['-r..'], ['3', '2', '1'])
60
log = self.runbzr("log -r ..")[0]
61
self.assertEquals(self.full_log, log)
122
63
def test_log_negative_begin_revspec_full_log(self):
123
self.make_linear_branch()
124
self.assertLogRevnos(['-r-3..'], ['3', '2', '1'])
65
log = self.runbzr("log -r -3..")[0]
66
self.assertEquals(self.full_log, log)
126
68
def test_log_negative_both_revspec_full_log(self):
127
self.make_linear_branch()
128
self.assertLogRevnos(['-r-3..-1'], ['3', '2', '1'])
70
log = self.runbzr("log -r -3..-1")[0]
71
self.assertEquals(self.full_log, log)
130
73
def test_log_negative_both_revspec_partial(self):
131
self.make_linear_branch()
132
self.assertLogRevnos(['-r-3..-2'], ['2', '1'])
75
log = self.runbzr("log -r -3..-2")[0]
76
self.assertTrue('revno: 1\n' in log)
77
self.assertTrue('revno: 2\n' in log)
78
self.assertTrue('revno: 3\n' not in log)
134
80
def test_log_negative_begin_revspec(self):
135
self.make_linear_branch()
136
self.assertLogRevnos(['-r-2..'], ['3', '2'])
138
def test_log_positive_revspecs(self):
139
self.make_linear_branch()
140
self.assertLogRevnos(['-r1..3'], ['3', '2', '1'])
142
def test_log_dotted_revspecs(self):
143
self.make_merged_branch()
144
self.assertLogRevnos(['-n0', '-r1..1.1.1'], ['1.1.1', '1'])
146
def test_log_limit(self):
147
tree = self.make_branch_and_tree('.')
148
# We want more commits than our batch size starts at
149
for pos in range(10):
150
tree.commit("%s" % pos)
151
self.assertLogRevnos(['--limit', '2'], ['10', '9'])
153
def test_log_limit_short(self):
154
self.make_linear_branch()
155
self.assertLogRevnos(['-l', '2'], ['3', '2'])
157
def test_log_change_revno(self):
158
self.make_linear_branch()
159
self.assertLogRevnos(['-c1'], ['1'])
161
def test_branch_revspec(self):
162
foo = self.make_branch_and_tree('foo')
163
bar = self.make_branch_and_tree('bar')
164
self.build_tree(['foo/foo.txt', 'bar/bar.txt'])
167
foo.commit(message='foo')
168
bar.commit(message='bar')
169
self.run_bzr('log -r branch:../bar', working_dir='foo')
170
self.assertEqual([bar.branch.get_rev_id(1)],
172
for r in self.get_captured_revisions()])
175
class TestLogExcludeCommonAncestry(TestLogWithLogCatcher):
177
def test_exclude_common_ancestry_simple_revnos(self):
178
self.make_linear_branch()
179
self.assertLogRevnos(['-r1..3', '--exclude-common-ancestry'],
183
class TestLogMergedLinearAncestry(TestLogWithLogCatcher):
186
super(TestLogMergedLinearAncestry, self).setUp()
187
# FIXME: Using a MemoryTree would be even better here (but until we
188
# stop calling run_bzr, there is no point) --vila 100118.
189
builder = branchbuilder.BranchBuilder(self.get_transport())
190
builder.start_series()
204
builder.build_snapshot('1', None, [
205
('add', ('', 'root-id', 'directory', ''))])
206
builder.build_snapshot('2', ['1'], [])
208
builder.build_snapshot('1.1.1', ['1'], [])
209
# merge branch into mainline
210
builder.build_snapshot('3', ['2', '1.1.1'], [])
211
# new commits in branch
212
builder.build_snapshot('1.1.2', ['1.1.1'], [])
213
builder.build_snapshot('1.1.3', ['1.1.2'], [])
214
# merge branch into mainline
215
builder.build_snapshot('4', ['3', '1.1.3'], [])
216
# merge mainline into branch
217
builder.build_snapshot('1.1.4', ['1.1.3', '4'], [])
218
# merge branch into mainline
219
builder.build_snapshot('5', ['4', '1.1.4'], [])
220
builder.finish_series()
223
self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4'],
224
['1.1.4', '4', '1.1.3', '1.1.2', '3', '1.1.1'])
225
def test_n0_forward(self):
226
self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4', '--forward'],
227
['3', '1.1.1', '4', '1.1.2', '1.1.3', '1.1.4'])
230
# starting from 1.1.4 we follow the left-hand ancestry
231
self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4'],
232
['1.1.4', '1.1.3', '1.1.2', '1.1.1'])
234
def test_n1_forward(self):
235
self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4', '--forward'],
236
['1.1.1', '1.1.2', '1.1.3', '1.1.4'])
239
class Test_GenerateAllRevisions(TestLogWithLogCatcher):
242
super(Test_GenerateAllRevisions, self).setUp()
243
builder = self.make_branch_with_many_merges()
244
b = builder.get_branch()
246
self.addCleanup(b.unlock)
249
def make_branch_with_many_merges(self, path='.', format=None):
250
builder = branchbuilder.BranchBuilder(self.get_transport())
251
builder.start_series()
252
# The graph below may look a bit complicated (and it may be but I've
253
# banged my head enough on it) but the bug requires at least dotted
254
# revnos *and* merged revisions below that.
255
builder.build_snapshot('1', None, [
256
('add', ('', 'root-id', 'directory', ''))])
257
builder.build_snapshot('2', ['1'], [])
258
builder.build_snapshot('1.1.1', ['1'], [])
259
builder.build_snapshot('2.1.1', ['2'], [])
260
builder.build_snapshot('3', ['2', '1.1.1'], [])
261
builder.build_snapshot('2.1.2', ['2.1.1'], [])
262
builder.build_snapshot('2.2.1', ['2.1.1'], [])
263
builder.build_snapshot('2.1.3', ['2.1.2', '2.2.1'], [])
264
builder.build_snapshot('4', ['3', '2.1.3'], [])
265
builder.build_snapshot('5', ['4', '2.1.2'], [])
266
builder.finish_series()
269
def test_not_an_ancestor(self):
270
self.assertRaises(errors.BzrCommandError,
271
log._generate_all_revisions,
272
self.branch, '1.1.1', '2.1.3', 'reverse',
273
delayed_graph_generation=True)
275
def test_wrong_order(self):
276
self.assertRaises(errors.BzrCommandError,
277
log._generate_all_revisions,
278
self.branch, '5', '2.1.3', 'reverse',
279
delayed_graph_generation=True)
281
def test_no_start_rev_id_with_end_rev_id_being_a_merge(self):
282
revs = log._generate_all_revisions(
283
self.branch, None, '2.1.3',
284
'reverse', delayed_graph_generation=True)
287
class TestLogRevSpecsWithPaths(TestLogWithLogCatcher):
289
def test_log_revno_n_path_wrong_namespace(self):
290
self.make_linear_branch('branch1')
291
self.make_linear_branch('branch2')
292
# There is no guarantee that a path exist between two arbitrary
294
self.run_bzr("log -r revno:2:branch1..revno:3:branch2", retcode=3)
296
def test_log_revno_n_path_correct_order(self):
297
self.make_linear_branch('branch2')
298
self.assertLogRevnos(['-rrevno:1:branch2..revno:3:branch2'],
301
def test_log_revno_n_path(self):
302
self.make_linear_branch('branch2')
303
self.assertLogRevnos(['-rrevno:1:branch2'],
305
rev_props = self.log_catcher.revisions[0].rev.properties
306
self.assertEqual('branch2', rev_props['branch-nick'])
309
class TestLogErrors(TestLog):
311
def test_log_zero_revspec(self):
312
self.make_minimal_branch()
313
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
316
def test_log_zero_begin_revspec(self):
317
self.make_linear_branch()
318
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
321
def test_log_zero_end_revspec(self):
322
self.make_linear_branch()
323
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
326
def test_log_nonexistent_revno(self):
327
self.make_minimal_branch()
328
self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
329
"does not exist in branch:"],
332
def test_log_nonexistent_dotted_revno(self):
333
self.make_minimal_branch()
334
self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
335
"does not exist in branch:"],
336
['log', '-r123.123'])
338
def test_log_change_nonexistent_revno(self):
339
self.make_minimal_branch()
340
self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
341
"does not exist in branch:"],
344
def test_log_change_nonexistent_dotted_revno(self):
345
self.make_minimal_branch()
346
self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
347
"does not exist in branch:"],
348
['log', '-c123.123'])
350
def test_log_change_single_revno_only(self):
351
self.make_minimal_branch()
352
self.run_bzr_error(['bzr: ERROR: Option --change does not'
353
' accept revision ranges'],
354
['log', '--change', '2..3'])
356
def test_log_change_incompatible_with_revision(self):
357
self.run_bzr_error(['bzr: ERROR: --revision and --change'
358
' are mutually exclusive'],
359
['log', '--change', '2', '--revision', '3'])
361
def test_log_nonexistent_file(self):
362
self.make_minimal_branch()
363
# files that don't exist in either the basis tree or working tree
364
# should give an error
365
out, err = self.run_bzr('log does-not-exist', retcode=3)
366
self.assertContainsRe(err,
367
'Path unknown at end or start of revision range: '
370
def test_log_reversed_revspecs(self):
371
self.make_linear_branch()
372
self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
373
'the end revision.\n',),
376
def test_log_reversed_dotted_revspecs(self):
377
self.make_merged_branch()
378
self.run_bzr_error(('bzr: ERROR: Start revision not found in '
379
'left-hand history of end revision.\n',),
382
def test_log_bad_message_re(self):
383
"""Bad --message argument gives a sensible message
385
See https://bugs.launchpad.net/bzr/+bug/251352
387
self.make_minimal_branch()
388
out, err = self.run_bzr(['log', '-m', '*'], retcode=3)
389
self.assertContainsRe(err, "ERROR.*Invalid pattern.*nothing to repeat")
390
self.assertNotContainsRe(err, "Unprintable exception")
391
self.assertEqual(out, '')
393
def test_log_unsupported_timezone(self):
394
self.make_linear_branch()
395
self.run_bzr_error(['bzr: ERROR: Unsupported timezone format "foo", '
396
'options are "utc", "original", "local".'],
397
['log', '--timezone', 'foo'])
399
def test_log_exclude_ancestry_no_range(self):
400
self.make_linear_branch()
401
self.run_bzr_error(['bzr: ERROR: --exclude-common-ancestry'
402
' requires -r with two revisions'],
403
['log', '--exclude-common-ancestry'])
405
def test_log_exclude_ancestry_single_revision(self):
406
self.make_merged_branch()
407
self.run_bzr_error(['bzr: ERROR: --exclude-common-ancestry'
408
' requires two different revisions'],
409
['log', '--exclude-common-ancestry',
412
class TestLogTags(TestLog):
414
def test_log_with_tags(self):
415
tree = self.make_linear_branch(format='dirstate-tags')
417
branch.tags.set_tag('tag1', branch.get_rev_id(1))
418
branch.tags.set_tag('tag1.1', branch.get_rev_id(1))
419
branch.tags.set_tag('tag3', branch.last_revision())
421
log = self.run_bzr("log -r-1")[0]
422
self.assertTrue('tags: tag3' in log)
424
log = self.run_bzr("log -r1")[0]
425
# I guess that we can't know the order of tags in the output
426
# since dicts are unordered, need to check both possibilities
427
self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)')
429
def test_merged_log_with_tags(self):
430
branch1_tree = self.make_linear_branch('branch1',
431
format='dirstate-tags')
432
branch1 = branch1_tree.branch
433
branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
434
branch1_tree.commit(message='foobar', allow_pointless=True)
435
branch1.tags.set_tag('tag1', branch1.last_revision())
436
# tags don't propagate if we don't merge
437
self.run_bzr('merge ../branch1', working_dir='branch2')
438
branch2_tree.commit(message='merge branch 1')
439
log = self.run_bzr("log -n0 -r-1", working_dir='branch2')[0]
440
self.assertContainsRe(log, r' tags: tag1')
441
log = self.run_bzr("log -n0 -r3.1.1", working_dir='branch2')[0]
442
self.assertContainsRe(log, r'tags: tag1')
445
class TestLogVerbose(TestLog):
448
super(TestLogVerbose, self).setUp()
449
self.make_minimal_branch()
451
def assertUseShortDeltaFormat(self, cmd):
452
log = self.run_bzr(cmd)[0]
453
# Check that we use the short status format
454
self.assertContainsRe(log, '(?m)^\s*A hello.txt$')
455
self.assertNotContainsRe(log, '(?m)^\s*added:$')
457
def assertUseLongDeltaFormat(self, cmd):
458
log = self.run_bzr(cmd)[0]
459
# Check that we use the long status format
460
self.assertNotContainsRe(log, '(?m)^\s*A hello.txt$')
461
self.assertContainsRe(log, '(?m)^\s*added:$')
463
def test_log_short_verbose(self):
464
self.assertUseShortDeltaFormat(['log', '--short', '-v'])
466
def test_log_short_verbose_verbose(self):
467
self.assertUseLongDeltaFormat(['log', '--short', '-vv'])
469
def test_log_long_verbose(self):
470
# Check that we use the long status format, ignoring the verbosity
472
self.assertUseLongDeltaFormat(['log', '--long', '-v'])
474
def test_log_long_verbose_verbose(self):
475
# Check that we use the long status format, ignoring the verbosity
477
self.assertUseLongDeltaFormat(['log', '--long', '-vv'])
480
class TestLogMerges(TestLogWithLogCatcher):
483
super(TestLogMerges, self).setUp()
484
self.make_branches_with_merges()
486
def make_branches_with_merges(self):
487
level0 = self.make_branch_and_tree('level0')
488
self.wt_commit(level0, 'in branch level0')
489
level1 = level0.bzrdir.sprout('level1').open_workingtree()
490
self.wt_commit(level1, 'in branch level1')
491
level2 = level1.bzrdir.sprout('level2').open_workingtree()
492
self.wt_commit(level2, 'in branch level2')
493
level1.merge_from_branch(level2.branch)
494
self.wt_commit(level1, 'merge branch level2')
495
level0.merge_from_branch(level1.branch)
496
self.wt_commit(level0, 'merge branch level1')
82
log = self.runbzr("log -r -2..")[0]
83
self.assertTrue('revno: 1\n' not in log)
84
self.assertTrue('revno: 2\n' in log)
85
self.assertTrue('revno: 3\n' in log)
87
def test_log_postive_revspecs(self):
89
log = self.runbzr("log -r 1..3")[0]
90
self.assertEquals(self.full_log, log)
93
class TestLogMerges(ExternalBase):
498
95
def test_merges_are_indented_by_level(self):
499
self.run_bzr(['log', '-n0'], working_dir='level0')
500
revnos_and_depth = [(r.revno, r.merge_depth)
501
for r in self.get_captured_revisions()]
502
self.assertEqual([('2', 0), ('1.1.2', 1), ('1.2.1', 2), ('1.1.1', 1),
504
[(r.revno, r.merge_depth)
505
for r in self.get_captured_revisions()])
507
def test_force_merge_revisions_off(self):
508
self.assertLogRevnos(['-n1'], ['2', '1'], working_dir='level0')
510
def test_force_merge_revisions_on(self):
511
self.assertLogRevnos(['-n0'], ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
512
working_dir='level0')
514
def test_include_merges(self):
515
# Confirm --include-merges gives the same output as -n0
516
self.assertLogRevnos(['--include-merges'],
517
['2', '1.1.2', '1.2.1', '1.1.1', '1'],
518
working_dir='level0')
519
self.assertLogRevnos(['--include-merges'],
520
['2', '1.1.2', '1.2.1', '1.1.1', '1'],
521
working_dir='level0')
522
out_im, err_im = self.run_bzr('log --include-merges',
523
working_dir='level0')
524
out_n0, err_n0 = self.run_bzr('log -n0', working_dir='level0')
525
self.assertEqual('', err_im)
526
self.assertEqual('', err_n0)
527
self.assertEqual(out_im, out_n0)
529
def test_force_merge_revisions_N(self):
530
self.assertLogRevnos(['-n2'],
531
['2', '1.1.2', '1.1.1', '1'],
532
working_dir='level0')
534
def test_merges_single_merge_rev(self):
535
self.assertLogRevnosAndDepths(['-n0', '-r1.1.2'],
536
[('1.1.2', 0), ('1.2.1', 1)],
537
working_dir='level0')
539
def test_merges_partial_range(self):
540
self.assertLogRevnosAndDepths(
541
['-n0', '-r1.1.1..1.1.2'],
542
[('1.1.2', 0), ('1.2.1', 1), ('1.1.1', 0)],
543
working_dir='level0')
545
def test_merges_partial_range_ignore_before_lower_bound(self):
546
"""Dont show revisions before the lower bound's merged revs"""
547
self.assertLogRevnosAndDepths(
548
['-n0', '-r1.1.2..2'],
549
[('2', 0), ('1.1.2', 1), ('1.2.1', 2)],
550
working_dir='level0')
553
class TestLogDiff(TestLogWithLogCatcher):
555
# FIXME: We need specific tests for each LogFormatter about how the diffs
556
# are displayed: --long indent them by depth, --short use a fixed
557
# indent and --line does't display them. -- vila 10019
560
super(TestLogDiff, self).setUp()
561
self.make_branch_with_diffs()
563
def make_branch_with_diffs(self):
564
level0 = self.make_branch_and_tree('level0')
565
self.build_tree(['level0/file1', 'level0/file2'])
568
self.wt_commit(level0, 'in branch level0')
570
level1 = level0.bzrdir.sprout('level1').open_workingtree()
571
self.build_tree_contents([('level1/file2', 'hello\n')])
572
self.wt_commit(level1, 'in branch level1')
573
level0.merge_from_branch(level1.branch)
574
self.wt_commit(level0, 'merge branch level1')
576
def _diff_file1_revno1(self):
577
return """=== added file 'file1'
578
--- file1\t1970-01-01 00:00:00 +0000
579
+++ file1\t2005-11-22 00:00:00 +0000
581
+contents of level0/file1
585
def _diff_file2_revno2(self):
586
return """=== modified file 'file2'
587
--- file2\t2005-11-22 00:00:00 +0000
588
+++ file2\t2005-11-22 00:00:01 +0000
590
-contents of level0/file2
595
def _diff_file2_revno1_1_1(self):
596
return """=== modified file 'file2'
597
--- file2\t2005-11-22 00:00:00 +0000
598
+++ file2\t2005-11-22 00:00:01 +0000
600
-contents of level0/file2
605
def _diff_file2_revno1(self):
606
return """=== added file 'file2'
607
--- file2\t1970-01-01 00:00:00 +0000
608
+++ file2\t2005-11-22 00:00:00 +0000
610
+contents of level0/file2
614
def assertLogRevnosAndDiff(self, args, expected,
616
self.run_bzr(['log', '-p'] + args, working_dir=working_dir)
617
expected_revnos_and_depths = [
618
(revno, depth) for revno, depth, diff in expected]
619
# Check the revnos and depths first to make debugging easier
620
self.assertEqual(expected_revnos_and_depths,
621
[(r.revno, r.merge_depth)
622
for r in self.get_captured_revisions()])
623
# Now check the diffs, adding the revno in case of failure
624
fmt = 'In revno %s\n%s'
625
for expected_rev, actual_rev in izip(expected,
626
self.get_captured_revisions()):
627
revno, depth, expected_diff = expected_rev
628
actual_diff = actual_rev.diff
629
self.assertEqualDiff(fmt % (revno, expected_diff),
630
fmt % (revno, actual_diff))
632
def test_log_diff_with_merges(self):
633
self.assertLogRevnosAndDiff(
635
[('2', 0, self._diff_file2_revno2()),
636
('1.1.1', 1, self._diff_file2_revno1_1_1()),
637
('1', 0, self._diff_file1_revno1()
638
+ self._diff_file2_revno1())],
639
working_dir='level0')
642
def test_log_diff_file1(self):
643
self.assertLogRevnosAndDiff(['-n0', 'file1'],
644
[('1', 0, self._diff_file1_revno1())],
645
working_dir='level0')
647
def test_log_diff_file2(self):
648
self.assertLogRevnosAndDiff(['-n1', 'file2'],
649
[('2', 0, self._diff_file2_revno2()),
650
('1', 0, self._diff_file2_revno1())],
651
working_dir='level0')
654
class TestLogUnicodeDiff(TestLog):
656
def test_log_show_diff_non_ascii(self):
657
# Smoke test for bug #328007 UnicodeDecodeError on 'log -p'
658
message = u'Message with \xb5'
659
body = 'Body with \xb5\n'
660
wt = self.make_branch_and_tree('.')
661
self.build_tree_contents([('foo', body)])
663
wt.commit(message=message)
664
# check that command won't fail with unicode error
665
# don't care about exact output because we have other tests for this
666
out,err = self.run_bzr('log -p --long')
667
self.assertNotEqual('', out)
668
self.assertEqual('', err)
669
out,err = self.run_bzr('log -p --short')
670
self.assertNotEqual('', out)
671
self.assertEqual('', err)
672
out,err = self.run_bzr('log -p --line')
673
self.assertNotEqual('', out)
674
self.assertEqual('', err)
677
class TestLogEncodings(tests.TestCaseInTempDir):
96
self.build_tree(['parent/'])
97
self.run_bzr('init', 'parent')
98
self.run_bzr('commit', '-m', 'first post', '--unchanged', 'parent')
99
self.run_bzr('branch', 'parent', 'child')
100
self.run_bzr('commit', '-m', 'branch 1', '--unchanged', 'child')
101
self.run_bzr('branch', 'child', 'smallerchild')
102
self.run_bzr('commit', '-m', 'branch 2', '--unchanged', 'smallerchild')
104
self.run_bzr('merge', '../smallerchild')
105
self.run_bzr('commit', '-m', 'merge branch 2')
106
os.chdir('../parent')
107
self.run_bzr('merge', '../child')
108
self.run_bzr('commit', '-m', 'merge branch 1')
109
out,err = self.run_bzr('log')
110
# the log will look something like:
111
# self.assertEqual("""\
112
#------------------------------------------------------------
114
#committer: Robert Collins <foo@example.com>
116
#timestamp: Tue 2006-03-28 22:31:40 +1100
119
# ------------------------------------------------------------
120
# merged: foo@example.com-20060328113140-91f43cfb46dc2863
121
# committer: Robert Collins <foo@example.com>
123
# timestamp: Tue 2006-03-28 22:31:40 +1100
126
# ------------------------------------------------------------
127
# merged: foo@example.com-20060328113140-1ba24f850a0ef573
128
# committer: Robert Collins <foo@example.com>
129
# branch nick: smallerchild
130
# timestamp: Tue 2006-03-28 22:31:40 +1100
133
# ------------------------------------------------------------
134
# merged: foo@example.com-20060328113140-5749a4757a8ac792
135
# committer: Robert Collins <foo@example.com>
137
# timestamp: Tue 2006-03-28 22:31:40 +1100
140
#------------------------------------------------------------
142
#committer: Robert Collins <foo@example.com>
144
#timestamp: Tue 2006-03-28 22:31:39 +1100
148
# but we dont have a nice pattern matcher hooked up yet, so:
149
# we check for the indenting of the commit message:
150
self.assertTrue(' merge branch 1' in out)
151
self.assertTrue(' merge branch 2' in out)
152
self.assertTrue(' branch 2' in out)
153
self.assertTrue(' branch 1' in out)
154
self.assertTrue(' first post' in out)
155
self.assertEqual('', err)
158
class TestLogEncodings(TestCaseInTempDir):
680
161
_message = u'Message with \xb5'