14
13
# You should have received a copy of the GNU General Public License
15
14
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
18
"""Black-box tests for bzr log."""
20
from itertools import izip
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]
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'])
41
110
def test_log_null_end_revspec(self):
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)
111
self.make_linear_branch()
112
self.assertLogRevnos(['-r1..'], ['3', '2', '1'])
53
114
def test_log_null_begin_revspec(self):
55
log = self.runbzr("log -r ..3")[0]
56
self.assertEquals(self.full_log, log)
115
self.make_linear_branch()
116
self.assertLogRevnos(['-r..3'], ['3', '2', '1'])
58
118
def test_log_null_both_revspecs(self):
60
log = self.runbzr("log -r ..")[0]
61
self.assertEquals(self.full_log, log)
119
self.make_linear_branch()
120
self.assertLogRevnos(['-r..'], ['3', '2', '1'])
63
122
def test_log_negative_begin_revspec_full_log(self):
65
log = self.runbzr("log -r -3..")[0]
66
self.assertEquals(self.full_log, log)
123
self.make_linear_branch()
124
self.assertLogRevnos(['-r-3..'], ['3', '2', '1'])
68
126
def test_log_negative_both_revspec_full_log(self):
70
log = self.runbzr("log -r -3..-1")[0]
71
self.assertEquals(self.full_log, log)
127
self.make_linear_branch()
128
self.assertLogRevnos(['-r-3..-1'], ['3', '2', '1'])
73
130
def test_log_negative_both_revspec_partial(self):
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)
131
self.make_linear_branch()
132
self.assertLogRevnos(['-r-3..-2'], ['2', '1'])
80
134
def test_log_negative_begin_revspec(self):
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):
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'])
162
class TestLogMergedLinearAncestry(TestLogWithLogCatcher):
165
super(TestLogMergedLinearAncestry, self).setUp()
166
# FIXME: Using a MemoryTree would be even better here (but until we
167
# stop calling run_bzr, there is no point) --vila 100118.
168
builder = branchbuilder.BranchBuilder(self.get_transport())
169
builder.start_series()
171
builder.build_snapshot('1', None, [
172
('add', ('', 'root-id', 'directory', ''))])
173
builder.build_snapshot('2', ['1'], [])
175
builder.build_snapshot('1.1.1', ['1'], [])
176
# merge branch into mainline
177
builder.build_snapshot('3', ['2', '1.1.1'], [])
178
# new commits in branch
179
builder.build_snapshot('1.1.2', ['1.1.1'], [])
180
builder.build_snapshot('1.1.3', ['1.1.2'], [])
181
# merge branch into mainline
182
builder.build_snapshot('4', ['3', '1.1.3'], [])
183
# merge mainline into branch
184
builder.build_snapshot('1.1.4', ['1.1.3', '4'], [])
185
# merge branch into mainline
186
builder.build_snapshot('5', ['4', '1.1.4'], [])
187
builder.finish_series()
190
self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4'],
191
['1.1.4', '4', '1.1.3', '1.1.2', '3', '1.1.1'])
192
def test_n0_forward(self):
193
self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4', '--forward'],
194
['3', '1.1.1', '4', '1.1.2', '1.1.3', '1.1.4'])
197
# starting from 1.1.4 we follow the left-hand ancestry
198
self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4'],
199
['1.1.4', '1.1.3', '1.1.2', '1.1.1'])
201
def test_n1_forward(self):
202
self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4', '--forward'],
203
['1.1.1', '1.1.2', '1.1.3', '1.1.4'])
206
class Test_GenerateAllRevisions(TestLogWithLogCatcher):
208
def make_branch_with_many_merges(self, path='.', format=None):
209
builder = branchbuilder.BranchBuilder(self.get_transport())
210
builder.start_series()
211
# The graph below may look a bit complicated (and it may be but I've
212
# banged my head enough on it) but the bug requires at least dotted
213
# revnos *and* merged revisions below that.
214
builder.build_snapshot('1', None, [
215
('add', ('', 'root-id', 'directory', ''))])
216
builder.build_snapshot('2', ['1'], [])
217
builder.build_snapshot('1.1.1', ['1'], [])
218
builder.build_snapshot('2.1.1', ['2'], [])
219
builder.build_snapshot('3', ['2', '1.1.1'], [])
220
builder.build_snapshot('2.1.2', ['2.1.1'], [])
221
builder.build_snapshot('2.2.1', ['2.1.1'], [])
222
builder.build_snapshot('2.1.3', ['2.1.2', '2.2.1'], [])
223
builder.build_snapshot('4', ['3', '2.1.3'], [])
224
builder.build_snapshot('5', ['4', '2.1.2'], [])
225
builder.finish_series()
228
def test_not_an_ancestor(self):
229
builder = self.make_branch_with_many_merges()
230
b = builder.get_branch()
232
self.addCleanup(b.unlock)
233
self.assertRaises(errors.BzrCommandError,
234
log._generate_all_revisions,
235
b, '1.1.1', '2.1.3', 'reverse',
236
delayed_graph_generation=True)
238
def test_wrong_order(self):
239
builder = self.make_branch_with_many_merges()
240
b = builder.get_branch()
242
self.addCleanup(b.unlock)
243
self.assertRaises(errors.BzrCommandError,
244
log._generate_all_revisions,
245
b, '5', '2.1.3', 'reverse',
246
delayed_graph_generation=True)
249
class TestLogRevSpecsWithPaths(TestLogWithLogCatcher):
251
def test_log_revno_n_path_wrong_namespace(self):
252
self.make_linear_branch('branch1')
253
self.make_linear_branch('branch2')
254
# There is no guarantee that a path exist between two arbitrary
256
self.run_bzr("log -r revno:2:branch1..revno:3:branch2", retcode=3)
258
def test_log_revno_n_path_correct_order(self):
259
self.make_linear_branch('branch2')
260
self.assertLogRevnos(['-rrevno:1:branch2..revno:3:branch2'],
263
def test_log_revno_n_path(self):
264
self.make_linear_branch('branch2')
265
self.assertLogRevnos(['-rrevno:1:branch2'],
267
rev_props = self.log_catcher.revisions[0].rev.properties
268
self.assertEqual('branch2', rev_props['branch-nick'])
271
class TestLogErrors(TestLog):
273
def test_log_zero_revspec(self):
274
self.make_minimal_branch()
275
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
278
def test_log_zero_begin_revspec(self):
279
self.make_linear_branch()
280
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
283
def test_log_zero_end_revspec(self):
284
self.make_linear_branch()
285
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
288
def test_log_nonexistent_revno(self):
289
self.make_minimal_branch()
290
self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
291
"does not exist in branch:"],
294
def test_log_nonexistent_dotted_revno(self):
295
self.make_minimal_branch()
296
self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
297
"does not exist in branch:"],
298
['log', '-r123.123'])
300
def test_log_change_nonexistent_revno(self):
301
self.make_minimal_branch()
302
self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
303
"does not exist in branch:"],
306
def test_log_change_nonexistent_dotted_revno(self):
307
self.make_minimal_branch()
308
self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
309
"does not exist in branch:"],
310
['log', '-c123.123'])
312
def test_log_change_single_revno_only(self):
313
self.make_minimal_branch()
314
self.run_bzr_error(['bzr: ERROR: Option --change does not'
315
' accept revision ranges'],
316
['log', '--change', '2..3'])
318
def test_log_change_incompatible_with_revision(self):
319
self.run_bzr_error(['bzr: ERROR: --revision and --change'
320
' are mutually exclusive'],
321
['log', '--change', '2', '--revision', '3'])
323
def test_log_nonexistent_file(self):
324
self.make_minimal_branch()
325
# files that don't exist in either the basis tree or working tree
326
# should give an error
327
out, err = self.run_bzr('log does-not-exist', retcode=3)
328
self.assertContainsRe(err,
329
'Path unknown at end or start of revision range: '
332
def test_log_reversed_revspecs(self):
333
self.make_linear_branch()
334
self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
335
'the end revision.\n',),
338
def test_log_reversed_dotted_revspecs(self):
339
self.make_merged_branch()
340
self.run_bzr_error(('bzr: ERROR: Start revision not found in '
341
'left-hand history of end revision.\n',),
344
def test_log_bad_message_re(self):
345
"""Bad --message argument gives a sensible message
347
See https://bugs.launchpad.net/bzr/+bug/251352
349
self.make_minimal_branch()
350
out, err = self.run_bzr(['log', '-m', '*'], retcode=3)
351
self.assertEqual("bzr: ERROR: Invalid regular expression"
352
" in log message filter"
354
": nothing to repeat\n", err)
355
self.assertEqual('', out)
357
def test_log_unsupported_timezone(self):
358
self.make_linear_branch()
359
self.run_bzr_error(['bzr: ERROR: Unsupported timezone format "foo", '
360
'options are "utc", "original", "local".'],
361
['log', '--timezone', 'foo'])
364
class TestLogTags(TestLog):
366
def test_log_with_tags(self):
367
tree = self.make_linear_branch(format='dirstate-tags')
369
branch.tags.set_tag('tag1', branch.get_rev_id(1))
370
branch.tags.set_tag('tag1.1', branch.get_rev_id(1))
371
branch.tags.set_tag('tag3', branch.last_revision())
373
log = self.run_bzr("log -r-1")[0]
374
self.assertTrue('tags: tag3' in log)
376
log = self.run_bzr("log -r1")[0]
377
# I guess that we can't know the order of tags in the output
378
# since dicts are unordered, need to check both possibilities
379
self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)')
381
def test_merged_log_with_tags(self):
382
branch1_tree = self.make_linear_branch('branch1',
383
format='dirstate-tags')
384
branch1 = branch1_tree.branch
385
branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
386
branch1_tree.commit(message='foobar', allow_pointless=True)
387
branch1.tags.set_tag('tag1', branch1.last_revision())
388
# tags don't propagate if we don't merge
389
self.run_bzr('merge ../branch1', working_dir='branch2')
390
branch2_tree.commit(message='merge branch 1')
391
log = self.run_bzr("log -n0 -r-1", working_dir='branch2')[0]
392
self.assertContainsRe(log, r' tags: tag1')
393
log = self.run_bzr("log -n0 -r3.1.1", working_dir='branch2')[0]
394
self.assertContainsRe(log, r'tags: tag1')
397
class TestLogVerbose(TestLog):
400
super(TestLogVerbose, self).setUp()
401
self.make_minimal_branch()
403
def assertUseShortDeltaFormat(self, cmd):
404
log = self.run_bzr(cmd)[0]
405
# Check that we use the short status format
406
self.assertContainsRe(log, '(?m)^\s*A hello.txt$')
407
self.assertNotContainsRe(log, '(?m)^\s*added:$')
409
def assertUseLongDeltaFormat(self, cmd):
410
log = self.run_bzr(cmd)[0]
411
# Check that we use the long status format
412
self.assertNotContainsRe(log, '(?m)^\s*A hello.txt$')
413
self.assertContainsRe(log, '(?m)^\s*added:$')
415
def test_log_short_verbose(self):
416
self.assertUseShortDeltaFormat(['log', '--short', '-v'])
418
def test_log_short_verbose_verbose(self):
419
self.assertUseLongDeltaFormat(['log', '--short', '-vv'])
421
def test_log_long_verbose(self):
422
# Check that we use the long status format, ignoring the verbosity
424
self.assertUseLongDeltaFormat(['log', '--long', '-v'])
426
def test_log_long_verbose_verbose(self):
427
# Check that we use the long status format, ignoring the verbosity
429
self.assertUseLongDeltaFormat(['log', '--long', '-vv'])
432
class TestLogMerges(TestLogWithLogCatcher):
435
super(TestLogMerges, self).setUp()
436
self.make_branches_with_merges()
438
def make_branches_with_merges(self):
439
level0 = self.make_branch_and_tree('level0')
440
self.wt_commit(level0, 'in branch level0')
441
level1 = level0.bzrdir.sprout('level1').open_workingtree()
442
self.wt_commit(level1, 'in branch level1')
443
level2 = level1.bzrdir.sprout('level2').open_workingtree()
444
self.wt_commit(level2, 'in branch level2')
445
level1.merge_from_branch(level2.branch)
446
self.wt_commit(level1, 'merge branch level2')
447
level0.merge_from_branch(level1.branch)
448
self.wt_commit(level0, 'merge branch level1')
95
450
def test_merges_are_indented_by_level(self):
96
self.build_tree(['parent/'])
97
self.run_bzr('init', 'parent')
98
self.run_bzr('commit', '-m', 'first post', '--unchanged', 'parent')
99
self.run_bzr('branch', 'parent', 'child')
100
self.run_bzr('commit', '-m', 'branch 1', '--unchanged', 'child')
101
self.run_bzr('branch', 'child', 'smallerchild')
102
self.run_bzr('commit', '-m', 'branch 2', '--unchanged', 'smallerchild')
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):
451
self.run_bzr(['log', '-n0'], working_dir='level0')
452
revnos_and_depth = [(r.revno, r.merge_depth)
453
for r in self.get_captured_revisions()]
454
self.assertEqual([('2', 0), ('1.1.2', 1), ('1.2.1', 2), ('1.1.1', 1),
456
[(r.revno, r.merge_depth)
457
for r in self.get_captured_revisions()])
459
def test_force_merge_revisions_off(self):
460
self.assertLogRevnos(['-n1'], ['2', '1'], working_dir='level0')
462
def test_force_merge_revisions_on(self):
463
self.assertLogRevnos(['-n0'], ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
464
working_dir='level0')
466
def test_include_merges(self):
467
# Confirm --include-merges gives the same output as -n0
468
self.assertLogRevnos(['--include-merges'],
469
['2', '1.1.2', '1.2.1', '1.1.1', '1'],
470
working_dir='level0')
471
self.assertLogRevnos(['--include-merges'],
472
['2', '1.1.2', '1.2.1', '1.1.1', '1'],
473
working_dir='level0')
474
out_im, err_im = self.run_bzr('log --include-merges',
475
working_dir='level0')
476
out_n0, err_n0 = self.run_bzr('log -n0', working_dir='level0')
477
self.assertEqual('', err_im)
478
self.assertEqual('', err_n0)
479
self.assertEqual(out_im, out_n0)
481
def test_force_merge_revisions_N(self):
482
self.assertLogRevnos(['-n2'],
483
['2', '1.1.2', '1.1.1', '1'],
484
working_dir='level0')
486
def test_merges_single_merge_rev(self):
487
self.assertLogRevnosAndDepths(['-n0', '-r1.1.2'],
488
[('1.1.2', 0), ('1.2.1', 1)],
489
working_dir='level0')
491
def test_merges_partial_range(self):
492
self.assertLogRevnosAndDepths(
493
['-n0', '-r1.1.1..1.1.2'],
494
[('1.1.2', 0), ('1.2.1', 1), ('1.1.1', 0)],
495
working_dir='level0')
497
def test_merges_partial_range_ignore_before_lower_bound(self):
498
"""Dont show revisions before the lower bound's merged revs"""
499
self.assertLogRevnosAndDepths(
500
['-n0', '-r1.1.2..2'],
501
[('2', 0), ('1.1.2', 1), ('1.2.1', 2)],
502
working_dir='level0')
505
class TestLogDiff(TestLogWithLogCatcher):
507
# FIXME: We need specific tests for each LogFormatter about how the diffs
508
# are displayed: --long indent them by depth, --short use a fixed
509
# indent and --line does't display them. -- vila 10019
512
super(TestLogDiff, self).setUp()
513
self.make_branch_with_diffs()
515
def make_branch_with_diffs(self):
516
level0 = self.make_branch_and_tree('level0')
517
self.build_tree(['level0/file1', 'level0/file2'])
520
self.wt_commit(level0, 'in branch level0')
522
level1 = level0.bzrdir.sprout('level1').open_workingtree()
523
self.build_tree_contents([('level1/file2', 'hello\n')])
524
self.wt_commit(level1, 'in branch level1')
525
level0.merge_from_branch(level1.branch)
526
self.wt_commit(level0, 'merge branch level1')
528
def _diff_file1_revno1(self):
529
return """=== added file 'file1'
530
--- file1\t1970-01-01 00:00:00 +0000
531
+++ file1\t2005-11-22 00:00:00 +0000
533
+contents of level0/file1
537
def _diff_file2_revno2(self):
538
return """=== modified file 'file2'
539
--- file2\t2005-11-22 00:00:00 +0000
540
+++ file2\t2005-11-22 00:00:01 +0000
542
-contents of level0/file2
547
def _diff_file2_revno1_1_1(self):
548
return """=== modified file 'file2'
549
--- file2\t2005-11-22 00:00:00 +0000
550
+++ file2\t2005-11-22 00:00:01 +0000
552
-contents of level0/file2
557
def _diff_file2_revno1(self):
558
return """=== added file 'file2'
559
--- file2\t1970-01-01 00:00:00 +0000
560
+++ file2\t2005-11-22 00:00:00 +0000
562
+contents of level0/file2
566
def assertLogRevnosAndDiff(self, args, expected,
568
self.run_bzr(['log', '-p'] + args, working_dir=working_dir)
569
expected_revnos_and_depths = [
570
(revno, depth) for revno, depth, diff in expected]
571
# Check the revnos and depths first to make debugging easier
572
self.assertEqual(expected_revnos_and_depths,
573
[(r.revno, r.merge_depth)
574
for r in self.get_captured_revisions()])
575
# Now check the diffs, adding the revno in case of failure
576
fmt = 'In revno %s\n%s'
577
for expected_rev, actual_rev in izip(expected,
578
self.get_captured_revisions()):
579
revno, depth, expected_diff = expected_rev
580
actual_diff = actual_rev.diff
581
self.assertEqualDiff(fmt % (revno, expected_diff),
582
fmt % (revno, actual_diff))
584
def test_log_diff_with_merges(self):
585
self.assertLogRevnosAndDiff(
587
[('2', 0, self._diff_file2_revno2()),
588
('1.1.1', 1, self._diff_file2_revno1_1_1()),
589
('1', 0, self._diff_file1_revno1()
590
+ self._diff_file2_revno1())],
591
working_dir='level0')
594
def test_log_diff_file1(self):
595
self.assertLogRevnosAndDiff(['-n0', 'file1'],
596
[('1', 0, self._diff_file1_revno1())],
597
working_dir='level0')
599
def test_log_diff_file2(self):
600
self.assertLogRevnosAndDiff(['-n1', 'file2'],
601
[('2', 0, self._diff_file2_revno2()),
602
('1', 0, self._diff_file2_revno1())],
603
working_dir='level0')
606
class TestLogUnicodeDiff(TestLog):
608
def test_log_show_diff_non_ascii(self):
609
# Smoke test for bug #328007 UnicodeDecodeError on 'log -p'
610
message = u'Message with \xb5'
611
body = 'Body with \xb5\n'
612
wt = self.make_branch_and_tree('.')
613
self.build_tree_contents([('foo', body)])
615
wt.commit(message=message)
616
# check that command won't fail with unicode error
617
# don't care about exact output because we have other tests for this
618
out,err = self.run_bzr('log -p --long')
619
self.assertNotEqual('', out)
620
self.assertEqual('', err)
621
out,err = self.run_bzr('log -p --short')
622
self.assertNotEqual('', out)
623
self.assertEqual('', err)
624
out,err = self.run_bzr('log -p --line')
625
self.assertNotEqual('', out)
626
self.assertEqual('', err)
629
class TestLogEncodings(tests.TestCaseInTempDir):
161
632
_message = u'Message with \xb5'