64
63
tree.commit(message='merge')
68
class TestLogWithLogCatcher(TestLog):
71
super(TestLogWithLogCatcher, self).setUp()
72
# Capture log formatter creations
73
class MyLogFormatter(test_log.LogCatcher):
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
# Break cycle with closure over self on cleanup by removing method
80
self.addCleanup(setattr, MyLogFormatter, "__new__", None)
83
# Always return our own log formatter class hijacking the
84
# default behavior (which requires setting up a config
87
self.overrideAttr(log.log_formatter_registry, 'get_default', getme)
89
def get_captured_revisions(self):
90
return self.log_catcher.revisions
92
def assertLogRevnos(self, args, expected_revnos, working_dir='.',
94
actual_out, actual_err = self.run_bzr(['log'] + args,
95
working_dir=working_dir)
96
self.assertEqual(out, actual_out)
97
self.assertEqual(err, actual_err)
98
self.assertEqual(expected_revnos,
99
[r.revno for r in self.get_captured_revisions()])
101
def assertLogRevnosAndDepths(self, args, expected_revnos_and_depths,
103
self.run_bzr(['log'] + args, working_dir=working_dir)
104
self.assertEqual(expected_revnos_and_depths,
105
[(r.revno, r.merge_depth)
106
for r in self.get_captured_revisions()])
109
class TestLogRevSpecs(TestLogWithLogCatcher):
111
def test_log_no_revspec(self):
112
self.make_linear_branch()
113
self.assertLogRevnos([], ['3', '2', '1'])
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)
75
def commit_options(self):
76
"""Use some mostly fixed values for commits to simplify tests.
78
Tests can use this function to get some commit attributes. The time
79
stamp is incremented at each commit.
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,
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))
94
class TestLogRevSpecs(TestLog):
115
96
def test_log_null_end_revspec(self):
116
97
self.make_linear_branch()
117
self.assertLogRevnos(['-r1..'], ['3', '2', '1'])
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)
106
full_log = self.run_bzr(['log'])[0]
107
log = self.run_bzr("log -r 1..")[0]
108
self.assertEqualDiff(log, full_log)
119
110
def test_log_null_begin_revspec(self):
120
111
self.make_linear_branch()
121
self.assertLogRevnos(['-r..3'], ['3', '2', '1'])
112
full_log = self.run_bzr(['log'])[0]
113
log = self.run_bzr("log -r ..3")[0]
114
self.assertEqualDiff(full_log, log)
123
116
def test_log_null_both_revspecs(self):
124
117
self.make_linear_branch()
125
self.assertLogRevnos(['-r..'], ['3', '2', '1'])
118
full_log = self.run_bzr(['log'])[0]
119
log = self.run_bzr("log -r ..")[0]
120
self.assertEqualDiff(full_log, log)
122
def test_log_zero_revspec(self):
123
self.make_minimal_branch()
124
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
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.'],
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.'],
127
137
def test_log_negative_begin_revspec_full_log(self):
128
138
self.make_linear_branch()
129
self.assertLogRevnos(['-r-3..'], ['3', '2', '1'])
139
full_log = self.run_bzr(['log'])[0]
140
log = self.run_bzr("log -r -3..")[0]
141
self.assertEqualDiff(full_log, log)
131
143
def test_log_negative_both_revspec_full_log(self):
132
144
self.make_linear_branch()
133
self.assertLogRevnos(['-r-3..-1'], ['3', '2', '1'])
145
full_log = self.run_bzr(['log'])[0]
146
log = self.run_bzr("log -r -3..-1")[0]
147
self.assertEqualDiff(full_log, log)
135
149
def test_log_negative_both_revspec_partial(self):
136
150
self.make_linear_branch()
137
self.assertLogRevnos(['-r-3..-2'], ['2', '1'])
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)
139
156
def test_log_negative_begin_revspec(self):
140
157
self.make_linear_branch()
141
self.assertLogRevnos(['-r-2..'], ['3', '2'])
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)
143
163
def test_log_positive_revspecs(self):
144
164
self.make_linear_branch()
145
self.assertLogRevnos(['-r1..3'], ['3', '2', '1'])
165
full_log = self.run_bzr(['log'])[0]
166
log = self.run_bzr("log -r 1..3")[0]
167
self.assertEqualDiff(full_log, log)
147
169
def test_log_dotted_revspecs(self):
148
170
self.make_merged_branch()
149
self.assertLogRevnos(['-n0', '-r1..1.1.1'], ['1.1.1', '1'])
151
def test_log_limit(self):
152
tree = self.make_branch_and_tree('.')
153
# We want more commits than our batch size starts at
154
for pos in range(10):
155
tree.commit("%s" % pos)
156
self.assertLogRevnos(['--limit', '2'], ['10', '9'])
158
def test_log_limit_short(self):
159
self.make_linear_branch()
160
self.assertLogRevnos(['-l', '2'], ['3', '2'])
162
def test_log_change_revno(self):
163
self.make_linear_branch()
164
self.assertLogRevnos(['-c1'], ['1'])
166
def test_branch_revspec(self):
167
foo = self.make_branch_and_tree('foo')
168
bar = self.make_branch_and_tree('bar')
169
self.build_tree(['foo/foo.txt', 'bar/bar.txt'])
172
foo.commit(message='foo')
173
bar.commit(message='bar')
174
self.run_bzr('log -r branch:../bar', working_dir='foo')
175
self.assertEqual([bar.branch.get_rev_id(1)],
177
for r in self.get_captured_revisions()])
180
class TestLogExcludeCommonAncestry(TestLogWithLogCatcher):
182
def test_exclude_common_ancestry_simple_revnos(self):
183
self.make_linear_branch()
184
self.assertLogRevnos(['-r1..3', '--exclude-common-ancestry'],
188
class TestLogMergedLinearAncestry(TestLogWithLogCatcher):
191
super(TestLogMergedLinearAncestry, self).setUp()
192
# FIXME: Using a MemoryTree would be even better here (but until we
193
# stop calling run_bzr, there is no point) --vila 100118.
194
builder = branchbuilder.BranchBuilder(self.get_transport())
195
builder.start_series()
209
builder.build_snapshot('1', None, [
210
('add', ('', 'root-id', 'directory', ''))])
211
builder.build_snapshot('2', ['1'], [])
213
builder.build_snapshot('1.1.1', ['1'], [])
214
# merge branch into mainline
215
builder.build_snapshot('3', ['2', '1.1.1'], [])
216
# new commits in branch
217
builder.build_snapshot('1.1.2', ['1.1.1'], [])
218
builder.build_snapshot('1.1.3', ['1.1.2'], [])
219
# merge branch into mainline
220
builder.build_snapshot('4', ['3', '1.1.3'], [])
221
# merge mainline into branch
222
builder.build_snapshot('1.1.4', ['1.1.3', '4'], [])
223
# merge branch into mainline
224
builder.build_snapshot('5', ['4', '1.1.4'], [])
225
builder.finish_series()
228
self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4'],
229
['1.1.4', '4', '1.1.3', '1.1.2', '3', '1.1.1'])
230
def test_n0_forward(self):
231
self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4', '--forward'],
232
['3', '1.1.1', '4', '1.1.2', '1.1.3', '1.1.4'])
235
# starting from 1.1.4 we follow the left-hand ancestry
236
self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4'],
237
['1.1.4', '1.1.3', '1.1.2', '1.1.1'])
239
def test_n1_forward(self):
240
self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4', '--forward'],
241
['1.1.1', '1.1.2', '1.1.3', '1.1.4'])
244
class Test_GenerateAllRevisions(TestLogWithLogCatcher):
247
super(Test_GenerateAllRevisions, self).setUp()
248
builder = self.make_branch_with_many_merges()
249
b = builder.get_branch()
251
self.addCleanup(b.unlock)
254
def make_branch_with_many_merges(self, path='.', format=None):
255
builder = branchbuilder.BranchBuilder(self.get_transport())
256
builder.start_series()
257
# The graph below may look a bit complicated (and it may be but I've
258
# banged my head enough on it) but the bug requires at least dotted
259
# revnos *and* merged revisions below that.
260
builder.build_snapshot('1', None, [
261
('add', ('', 'root-id', 'directory', ''))])
262
builder.build_snapshot('2', ['1'], [])
263
builder.build_snapshot('1.1.1', ['1'], [])
264
builder.build_snapshot('2.1.1', ['2'], [])
265
builder.build_snapshot('3', ['2', '1.1.1'], [])
266
builder.build_snapshot('2.1.2', ['2.1.1'], [])
267
builder.build_snapshot('2.2.1', ['2.1.1'], [])
268
builder.build_snapshot('2.1.3', ['2.1.2', '2.2.1'], [])
269
builder.build_snapshot('4', ['3', '2.1.3'], [])
270
builder.build_snapshot('5', ['4', '2.1.2'], [])
271
builder.finish_series()
274
def test_not_an_ancestor(self):
275
self.assertRaises(errors.BzrCommandError,
276
log._generate_all_revisions,
277
self.branch, '1.1.1', '2.1.3', 'reverse',
278
delayed_graph_generation=True)
280
def test_wrong_order(self):
281
self.assertRaises(errors.BzrCommandError,
282
log._generate_all_revisions,
283
self.branch, '5', '2.1.3', 'reverse',
284
delayed_graph_generation=True)
286
def test_no_start_rev_id_with_end_rev_id_being_a_merge(self):
287
revs = log._generate_all_revisions(
288
self.branch, None, '2.1.3',
289
'reverse', delayed_graph_generation=True)
292
class TestLogRevSpecsWithPaths(TestLogWithLogCatcher):
294
def test_log_revno_n_path_wrong_namespace(self):
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))
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',),
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',),
186
def test_log_revno_n_path(self):
295
187
self.make_linear_branch('branch1')
296
188
self.make_linear_branch('branch2')
297
# There is no guarantee that a path exist between two arbitrary
299
self.run_bzr("log -r revno:2:branch1..revno:3:branch2", retcode=3)
301
def test_log_revno_n_path_correct_order(self):
302
self.make_linear_branch('branch2')
303
self.assertLogRevnos(['-rrevno:1:branch2..revno:3:branch2'],
306
def test_log_revno_n_path(self):
307
self.make_linear_branch('branch2')
308
self.assertLogRevnos(['-rrevno:1:branch2'],
310
rev_props = self.log_catcher.revisions[0].rev.properties
311
self.assertEqual('branch2', rev_props['branch-nick'])
314
class TestLogErrors(TestLog):
316
def test_log_zero_revspec(self):
317
self.make_minimal_branch()
318
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
321
def test_log_zero_begin_revspec(self):
322
self.make_linear_branch()
323
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
326
def test_log_zero_end_revspec(self):
327
self.make_linear_branch()
328
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
190
self.run_bzr("log -r revno:2:branch1..revno:3:branch2", retcode=3)[0]
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)
331
201
def test_log_nonexistent_revno(self):
332
202
self.make_minimal_branch()
333
self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
334
"does not exist in branch:"],
203
(out, err) = self.run_bzr_error(
204
["bzr: ERROR: Requested revision: '1234' "
205
"does not exist in branch:"],
337
208
def test_log_nonexistent_dotted_revno(self):
338
209
self.make_minimal_branch()
339
self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
340
"does not exist in branch:"],
341
['log', '-r123.123'])
210
(out, err) = self.run_bzr_error(
211
["bzr: ERROR: Requested revision: '123.123' "
212
"does not exist in branch:"],
213
['log', '-r123.123'])
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)
343
221
def test_log_change_nonexistent_revno(self):
344
222
self.make_minimal_branch()
345
self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
346
"does not exist in branch:"],
223
(out, err) = self.run_bzr_error(
224
["bzr: ERROR: Requested revision: '1234' "
225
"does not exist in branch:"],
349
228
def test_log_change_nonexistent_dotted_revno(self):
350
229
self.make_minimal_branch()
351
self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
352
"does not exist in branch:"],
353
['log', '-c123.123'])
230
(out, err) = self.run_bzr_error(
231
["bzr: ERROR: Requested revision: '123.123' "
232
"does not exist in branch:"],
233
['log', '-c123.123'])
355
235
def test_log_change_single_revno_only(self):
356
236
self.make_minimal_branch()
513
373
def make_branches_with_merges(self):
514
374
level0 = self.make_branch_and_tree('level0')
515
self.wt_commit(level0, 'in branch level0')
375
level0.commit(message='in branch level0', **self.commit_options())
516
377
level1 = level0.bzrdir.sprout('level1').open_workingtree()
517
self.wt_commit(level1, 'in branch level1')
378
level1.commit(message='in branch level1', **self.commit_options())
518
380
level2 = level1.bzrdir.sprout('level2').open_workingtree()
519
self.wt_commit(level2, 'in branch level2')
381
level2.commit(message='in branch level2', **self.commit_options())
520
383
level1.merge_from_branch(level2.branch)
521
self.wt_commit(level1, 'merge branch level2')
384
level1.commit(message='merge branch level2', **self.commit_options())
522
386
level0.merge_from_branch(level1.branch)
523
self.wt_commit(level0, 'merge branch level1')
387
level0.commit(message='merge branch level1', **self.commit_options())
525
389
def test_merges_are_indented_by_level(self):
526
self.run_bzr(['log', '-n0'], working_dir='level0')
527
revnos_and_depth = [(r.revno, r.merge_depth)
528
for r in self.get_captured_revisions()]
529
self.assertEqual([('2', 0), ('1.1.2', 1), ('1.2.1', 2), ('1.1.1', 1),
531
[(r.revno, r.merge_depth)
532
for r in self.get_captured_revisions()])
391
------------------------------------------------------------
393
committer: Lorem Ipsum <test@example.com>
398
------------------------------------------------------------
400
committer: Lorem Ipsum <test@example.com>
405
------------------------------------------------------------
407
committer: Lorem Ipsum <test@example.com>
412
------------------------------------------------------------
414
committer: Lorem Ipsum <test@example.com>
419
------------------------------------------------------------
421
committer: Lorem Ipsum <test@example.com>
427
self.check_log(expected, ['-n0'])
534
429
def test_force_merge_revisions_off(self):
535
self.assertLogRevnos(['-n1'], ['2', '1'], working_dir='level0')
431
------------------------------------------------------------
433
committer: Lorem Ipsum <test@example.com>
438
------------------------------------------------------------
440
committer: Lorem Ipsum <test@example.com>
446
self.check_log(expected, ['--long', '-n1'])
537
448
def test_force_merge_revisions_on(self):
538
self.assertLogRevnos(['-n0'], ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
539
working_dir='level0')
450
2 Lorem Ipsum\t2005-11-22 [merge]
453
1.1.2 Lorem Ipsum\t2005-11-22 [merge]
456
1.2.1 Lorem Ipsum\t2005-11-22
459
1.1.1 Lorem Ipsum\t2005-11-22
462
1 Lorem Ipsum\t2005-11-22
466
self.check_log(expected, ['--short', '-n0'])
541
468
def test_include_merges(self):
542
469
# Confirm --include-merges gives the same output as -n0
543
msg = ("The option '--include-merges' to 'bzr log' "
544
"has been deprecated in bzr 2.5. "
545
"Please use '--include-merged' instead.\n")
546
self.assertLogRevnos(['--include-merges'],
547
['2', '1.1.2', '1.2.1', '1.1.1', '1'],
548
working_dir='level0', err=msg)
549
self.assertLogRevnos(['--include-merges'],
550
['2', '1.1.2', '1.2.1', '1.1.1', '1'],
551
working_dir='level0', err=msg)
552
470
out_im, err_im = self.run_bzr('log --include-merges',
553
471
working_dir='level0')
554
472
out_n0, err_n0 = self.run_bzr('log -n0', working_dir='level0')
555
self.assertEqual(msg, err_im)
473
self.assertEqual('', err_im)
556
474
self.assertEqual('', err_n0)
557
475
self.assertEqual(out_im, out_n0)
559
def test_include_merged(self):
560
# Confirm --include-merged gives the same output as -n0
561
expected = ['2', '1.1.2', '1.2.1', '1.1.1', '1']
562
self.assertLogRevnos(['--include-merged'],
563
expected, working_dir='level0')
564
self.assertLogRevnos(['--include-merged'],
565
expected, working_dir='level0')
567
477
def test_force_merge_revisions_N(self):
568
self.assertLogRevnos(['-n2'],
569
['2', '1.1.2', '1.1.1', '1'],
570
working_dir='level0')
479
2 Lorem Ipsum\t2005-11-22 [merge]
482
1.1.2 Lorem Ipsum\t2005-11-22 [merge]
485
1.1.1 Lorem Ipsum\t2005-11-22
488
1 Lorem Ipsum\t2005-11-22
492
self.check_log(expected, ['--short', '-n2'])
572
494
def test_merges_single_merge_rev(self):
573
self.assertLogRevnosAndDepths(['-n0', '-r1.1.2'],
574
[('1.1.2', 0), ('1.2.1', 1)],
575
working_dir='level0')
496
------------------------------------------------------------
498
committer: Lorem Ipsum <test@example.com>
503
------------------------------------------------------------
505
committer: Lorem Ipsum <test@example.com>
511
self.check_log(expected, ['-n0', '-r1.1.2'])
577
513
def test_merges_partial_range(self):
578
self.assertLogRevnosAndDepths(
579
['-n0', '-r1.1.1..1.1.2'],
580
[('1.1.2', 0), ('1.2.1', 1), ('1.1.1', 0)],
581
working_dir='level0')
583
def test_merges_partial_range_ignore_before_lower_bound(self):
584
"""Dont show revisions before the lower bound's merged revs"""
585
self.assertLogRevnosAndDepths(
586
['-n0', '-r1.1.2..2'],
587
[('2', 0), ('1.1.2', 1), ('1.2.1', 2)],
588
working_dir='level0')
590
def test_omit_merges_with_sidelines(self):
591
self.assertLogRevnos(['--omit-merges', '-n0'], ['1.2.1', '1.1.1', '1'],
592
working_dir='level0')
594
def test_omit_merges_without_sidelines(self):
595
self.assertLogRevnos(['--omit-merges', '-n1'], ['1'],
596
working_dir='level0')
599
class TestLogDiff(TestLogWithLogCatcher):
601
# FIXME: We need specific tests for each LogFormatter about how the diffs
602
# are displayed: --long indent them by depth, --short use a fixed
603
# indent and --line does't display them. -- vila 10019
515
------------------------------------------------------------
517
committer: Lorem Ipsum <test@example.com>
522
------------------------------------------------------------
524
committer: Lorem Ipsum <test@example.com>
529
------------------------------------------------------------
531
committer: Lorem Ipsum <test@example.com>
537
self.check_log(expected, ['-n0', '-r1.1.1..1.1.2'])
540
class TestLogDiff(TestLog):
606
543
super(TestLogDiff, self).setUp()
611
548
self.build_tree(['level0/file1', 'level0/file2'])
612
549
level0.add('file1')
613
550
level0.add('file2')
614
self.wt_commit(level0, 'in branch level0')
551
level0.commit(message='in branch level0', **self.commit_options())
616
553
level1 = level0.bzrdir.sprout('level1').open_workingtree()
617
554
self.build_tree_contents([('level1/file2', 'hello\n')])
618
self.wt_commit(level1, 'in branch level1')
555
level1.commit(message='in branch level1', **self.commit_options())
619
556
level0.merge_from_branch(level1.branch)
620
self.wt_commit(level0, 'merge branch level1')
557
level0.commit(message='merge branch level1', **self.commit_options())
622
def _diff_file1_revno1(self):
623
return """=== added file 'file1'
559
def test_log_show_diff_long_with_merges(self):
560
out,err = self.run_bzr('log -p -n0')
561
self.assertEqual('', err)
562
log = test_log.normalize_log(out)
564
------------------------------------------------------------
566
committer: Lorem Ipsum <test@example.com>
572
=== modified file 'file2'
573
--- file2\t2005-11-22 00:00:01 +0000
574
+++ file2\t2005-11-22 00:00:02 +0000
576
-contents of level0/file2
578
------------------------------------------------------------
580
committer: Lorem Ipsum <test@example.com>
586
=== modified file 'file2'
587
--- file2\t2005-11-22 00:00:01 +0000
588
+++ file2\t2005-11-22 00:00:02 +0000
590
-contents of level0/file2
592
------------------------------------------------------------
594
committer: Lorem Ipsum <test@example.com>
600
=== added file 'file1'
624
601
--- file1\t1970-01-01 00:00:00 +0000
625
+++ file1\t2005-11-22 00:00:00 +0000
602
+++ file1\t2005-11-22 00:00:01 +0000
627
604
+contents of level0/file1
631
def _diff_file2_revno2(self):
632
return """=== modified file 'file2'
633
--- file2\t2005-11-22 00:00:00 +0000
634
+++ file2\t2005-11-22 00:00:01 +0000
636
-contents of level0/file2
641
def _diff_file2_revno1_1_1(self):
642
return """=== modified file 'file2'
643
--- file2\t2005-11-22 00:00:00 +0000
644
+++ file2\t2005-11-22 00:00:01 +0000
646
-contents of level0/file2
651
def _diff_file2_revno1(self):
652
return """=== added file 'file2'
606
=== added file 'file2'
653
607
--- file2\t1970-01-01 00:00:00 +0000
654
+++ file2\t2005-11-22 00:00:00 +0000
608
+++ file2\t2005-11-22 00:00:01 +0000
656
610
+contents of level0/file2
660
def assertLogRevnosAndDiff(self, args, expected,
662
self.run_bzr(['log', '-p'] + args, working_dir=working_dir)
663
expected_revnos_and_depths = [
664
(revno, depth) for revno, depth, diff in expected]
665
# Check the revnos and depths first to make debugging easier
666
self.assertEqual(expected_revnos_and_depths,
667
[(r.revno, r.merge_depth)
668
for r in self.get_captured_revisions()])
669
# Now check the diffs, adding the revno in case of failure
670
fmt = 'In revno %s\n%s'
671
for expected_rev, actual_rev in izip(expected,
672
self.get_captured_revisions()):
673
revno, depth, expected_diff = expected_rev
674
actual_diff = actual_rev.diff
675
self.assertEqualDiff(fmt % (revno, expected_diff),
676
fmt % (revno, actual_diff))
678
def test_log_diff_with_merges(self):
679
self.assertLogRevnosAndDiff(
681
[('2', 0, self._diff_file2_revno2()),
682
('1.1.1', 1, self._diff_file2_revno1_1_1()),
683
('1', 0, self._diff_file1_revno1()
684
+ self._diff_file2_revno1())],
685
working_dir='level0')
688
def test_log_diff_file1(self):
689
self.assertLogRevnosAndDiff(['-n0', 'file1'],
690
[('1', 0, self._diff_file1_revno1())],
691
working_dir='level0')
693
def test_log_diff_file2(self):
694
self.assertLogRevnosAndDiff(['-n1', 'file2'],
695
[('2', 0, self._diff_file2_revno2()),
696
('1', 0, self._diff_file2_revno1())],
697
working_dir='level0')
612
self.check_log(expected, ['-p', '-n0'])
614
def test_log_show_diff_short(self):
616
2 Lorem Ipsum\t2005-11-22 [merge]
618
=== modified file 'file2'
619
--- file2\t2005-11-22 00:00:01 +0000
620
+++ file2\t2005-11-22 00:00:02 +0000
622
-contents of level0/file2
625
1 Lorem Ipsum\t2005-11-22
627
=== added file 'file1'
628
--- file1\t1970-01-01 00:00:00 +0000
629
+++ file1\t2005-11-22 00:00:01 +0000
631
+contents of level0/file1
632
\x20\x20\x20\x20\x20\x20
633
=== added file 'file2'
634
--- file2\t1970-01-01 00:00:00 +0000
635
+++ file2\t2005-11-22 00:00:01 +0000
637
+contents of level0/file2
639
Use --include-merges or -n0 to see merged revisions.
641
self.check_log(expected, ['-p', '--short'])
643
def test_log_show_diff_line(self):
644
# Not supported by this formatter so expect plain output
646
2: Lorem Ipsum 2005-11-22 [merge] merge branch level1
647
1: Lorem Ipsum 2005-11-22 in branch level0
649
self.check_log(expected, ['-p', '--line'])
651
def test_log_show_diff_file1(self):
652
"""Only the diffs for the given file are to be shown"""
654
1 Lorem Ipsum\t2005-11-22
656
=== added file 'file1'
657
--- file1\t1970-01-01 00:00:00 +0000
658
+++ file1\t2005-11-22 00:00:01 +0000
660
+contents of level0/file1
663
self.check_log(expected, ['-p', '--short', 'file1'])
665
def test_log_show_diff_file2(self):
666
"""Only the diffs for the given file are to be shown"""
668
2 Lorem Ipsum\t2005-11-22 [merge]
670
=== modified file 'file2'
671
--- file2\t2005-11-22 00:00:01 +0000
672
+++ file2\t2005-11-22 00:00:02 +0000
674
-contents of level0/file2
677
1 Lorem Ipsum\t2005-11-22
679
=== added file 'file2'
680
--- file2\t1970-01-01 00:00:00 +0000
681
+++ file2\t2005-11-22 00:00:01 +0000
683
+contents of level0/file2
685
Use --include-merges or -n0 to see merged revisions.
687
self.check_log(expected, ['-p', '--short', 'file2'])
700
690
class TestLogUnicodeDiff(TestLog):
852
845
tree.commit('remove file1')
853
846
os.chdir('parent')
855
# FIXME: It would be good to parametrize the following tests against all
856
# formatters. But the revisions selection is not *currently* part of the
857
# LogFormatter contract, so using LogCatcher is sufficient -- vila 100118
858
def test_log_file1(self):
860
self.assertLogRevnos(['-n0', 'file1'], ['1'])
862
def test_log_file2(self):
865
self.assertLogRevnos(['-n0', 'file2'], ['4', '3.1.1', '2'])
866
# file2 in a merge revision
867
self.assertLogRevnos(['-n0', '-r3.1.1', 'file2'], ['3.1.1'])
868
# file2 in a mainline revision
869
self.assertLogRevnos(['-n0', '-r4', 'file2'], ['4', '3.1.1'])
870
# file2 since a revision
871
self.assertLogRevnos(['-n0', '-r3..', 'file2'], ['4', '3.1.1'])
872
# file2 up to a revision
873
self.assertLogRevnos(['-n0', '-r..3', 'file2'], ['2'])
875
def test_log_file3(self):
877
self.assertLogRevnos(['-n0', 'file3'], ['3'])
848
def test_log_file(self):
849
"""The log for a particular file should only list revs for that file"""
851
log = self.run_bzr('log -n0 file1')[0]
852
self.assertContainsRe(log, 'revno: 1\n')
853
self.assertNotContainsRe(log, 'revno: 2\n')
854
self.assertNotContainsRe(log, 'revno: 3\n')
855
self.assertNotContainsRe(log, 'revno: 3.1.1\n')
856
self.assertNotContainsRe(log, 'revno: 4 ')
857
log = self.run_bzr('log -n0 file2')[0]
858
self.assertNotContainsRe(log, 'revno: 1\n')
859
self.assertContainsRe(log, 'revno: 2\n')
860
self.assertNotContainsRe(log, 'revno: 3\n')
861
self.assertContainsRe(log, 'revno: 3.1.1\n')
862
self.assertContainsRe(log, 'revno: 4 ')
863
log = self.run_bzr('log -n0 file3')[0]
864
self.assertNotContainsRe(log, 'revno: 1\n')
865
self.assertNotContainsRe(log, 'revno: 2\n')
866
self.assertContainsRe(log, 'revno: 3\n')
867
self.assertNotContainsRe(log, 'revno: 3.1.1\n')
868
self.assertNotContainsRe(log, 'revno: 4 ')
869
log = self.run_bzr('log -n0 -r3.1.1 file2')[0]
870
self.assertNotContainsRe(log, 'revno: 1\n')
871
self.assertNotContainsRe(log, 'revno: 2\n')
872
self.assertNotContainsRe(log, 'revno: 3\n')
873
self.assertContainsRe(log, 'revno: 3.1.1\n')
874
self.assertNotContainsRe(log, 'revno: 4 ')
875
log = self.run_bzr('log -n0 -r4 file2')[0]
876
self.assertNotContainsRe(log, 'revno: 1\n')
877
self.assertNotContainsRe(log, 'revno: 2\n')
878
self.assertNotContainsRe(log, 'revno: 3\n')
879
self.assertContainsRe(log, 'revno: 3.1.1\n')
880
self.assertContainsRe(log, 'revno: 4 ')
881
log = self.run_bzr('log -n0 -r3.. file2')[0]
882
self.assertNotContainsRe(log, 'revno: 1\n')
883
self.assertNotContainsRe(log, 'revno: 2\n')
884
self.assertNotContainsRe(log, 'revno: 3\n')
885
self.assertContainsRe(log, 'revno: 3.1.1\n')
886
self.assertContainsRe(log, 'revno: 4 ')
887
log = self.run_bzr('log -n0 -r..3 file2')[0]
888
self.assertNotContainsRe(log, 'revno: 1\n')
889
self.assertContainsRe(log, 'revno: 2\n')
890
self.assertNotContainsRe(log, 'revno: 3\n')
891
self.assertNotContainsRe(log, 'revno: 3.1.1\n')
892
self.assertNotContainsRe(log, 'revno: 4 ')
879
894
def test_log_file_historical_missing(self):
880
895
# Check logging a deleted file gives an error if the
906
933
self.assertContainsRe(err, err_msg)
908
935
# Check we can see a renamed file if we give the right end revision
909
self.assertLogRevnos(['-r..4', 'file3'], ['3'])
912
class TestLogMultiple(TestLogWithLogCatcher):
936
log, err = self.run_bzr('log -r..4 file3')
937
self.assertEquals('', err)
938
self.assertNotContainsRe(log, 'revno: 1\n')
939
self.assertNotContainsRe(log, 'revno: 2\n')
940
self.assertContainsRe(log, 'revno: 3\n')
941
self.assertNotContainsRe(log, 'revno: 3.1.1\n')
942
self.assertNotContainsRe(log, 'revno: 4 ')
944
def test_line_log_file(self):
945
"""The line log for a file should only list relevant mainline revs"""
946
# Note: this also implicitly covers the short logging case.
947
# We test using --line in preference to --short because matching
948
# revnos in the output of --line is more reliable.
951
# full history of file1
952
log = self.run_bzr('log --line file1')[0]
953
self.assertContainsRe(log, '^1:', re.MULTILINE)
954
self.assertNotContainsRe(log, '^2:', re.MULTILINE)
955
self.assertNotContainsRe(log, '^3:', re.MULTILINE)
956
self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
957
self.assertNotContainsRe(log, '^4:', re.MULTILINE)
959
# full history of file2
960
log = self.run_bzr('log --line file2')[0]
961
self.assertNotContainsRe(log, '^1:', re.MULTILINE)
962
self.assertContainsRe(log, '^2:', re.MULTILINE)
963
self.assertNotContainsRe(log, '^3:', re.MULTILINE)
964
self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
965
self.assertContainsRe(log, '^4:', re.MULTILINE)
967
# full history of file3
968
log = self.run_bzr('log --line file3')[0]
969
self.assertNotContainsRe(log, '^1:', re.MULTILINE)
970
self.assertNotContainsRe(log, '^2:', re.MULTILINE)
971
self.assertContainsRe(log, '^3:', re.MULTILINE)
972
self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
973
self.assertNotContainsRe(log, '^4:', re.MULTILINE)
975
# file in a merge revision
976
log = self.run_bzr('log --line -r3.1.1 file2')[0]
977
self.assertNotContainsRe(log, '^1:', re.MULTILINE)
978
self.assertNotContainsRe(log, '^2:', re.MULTILINE)
979
self.assertNotContainsRe(log, '^3:', re.MULTILINE)
980
self.assertContainsRe(log, '^3.1.1:', re.MULTILINE)
981
self.assertNotContainsRe(log, '^4:', re.MULTILINE)
983
# file in a mainline revision
984
log = self.run_bzr('log --line -r4 file2')[0]
985
self.assertNotContainsRe(log, '^1:', re.MULTILINE)
986
self.assertNotContainsRe(log, '^2:', re.MULTILINE)
987
self.assertNotContainsRe(log, '^3:', re.MULTILINE)
988
self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
989
self.assertContainsRe(log, '^4:', re.MULTILINE)
991
# file since a revision
992
log = self.run_bzr('log --line -r3.. file2')[0]
993
self.assertNotContainsRe(log, '^1:', re.MULTILINE)
994
self.assertNotContainsRe(log, '^2:', re.MULTILINE)
995
self.assertNotContainsRe(log, '^3:', re.MULTILINE)
996
self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
997
self.assertContainsRe(log, '^4:', re.MULTILINE)
999
# file up to a revision
1000
log = self.run_bzr('log --line -r..3 file2')[0]
1001
self.assertNotContainsRe(log, '^1:', re.MULTILINE)
1002
self.assertContainsRe(log, '^2:', re.MULTILINE)
1003
self.assertNotContainsRe(log, '^3:', re.MULTILINE)
1004
self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
1005
self.assertNotContainsRe(log, '^4:', re.MULTILINE)
1008
class TestLogMultiple(tests.TestCaseWithTransport):
914
1010
def prepare_tree(self):
915
1011
tree = self.make_branch_and_tree('parent')
938
1034
tree.commit(message='merge child branch')
939
1035
os.chdir('parent')
1037
def assertRevnos(self, paths_str, expected_revnos):
1038
# confirm the revision numbers in log --line output are those expected
1039
out, err = self.run_bzr('log --line -n0 %s' % (paths_str,))
1040
self.assertEqual('', err)
1041
revnos = [s.split(':', 1)[0].lstrip() for s in out.splitlines()]
1042
self.assertEqual(expected_revnos, revnos)
941
1044
def test_log_files(self):
942
1045
"""The log for multiple file should only list revs for those files"""
943
1046
self.prepare_tree()
944
self.assertLogRevnos(['file1', 'file2', 'dir1/dir2/file3'],
945
['6', '5.1.1', '3', '2', '1'])
1047
self.assertRevnos('file1 file2 dir1/dir2/file3',
1048
['6', '5.1.1', '3', '2', '1'])
947
1050
def test_log_directory(self):
948
1051
"""The log for a directory should show all nested files."""
949
1052
self.prepare_tree()
950
self.assertLogRevnos(['dir1'], ['5', '3'])
1053
self.assertRevnos('dir1', ['5', '3'])
952
1055
def test_log_nested_directory(self):
953
1056
"""The log for a directory should show all nested files."""
954
1057
self.prepare_tree()
955
self.assertLogRevnos(['dir1/dir2'], ['3'])
1058
self.assertRevnos('dir1/dir2', ['3'])
957
1060
def test_log_in_nested_directory(self):
958
1061
"""The log for a directory should show all nested files."""
959
1062
self.prepare_tree()
960
1063
os.chdir("dir1")
961
self.assertLogRevnos(['.'], ['5', '3'])
1064
self.assertRevnos('.', ['5', '3'])
963
1066
def test_log_files_and_directories(self):
964
1067
"""Logging files and directories together should be fine."""
965
1068
self.prepare_tree()
966
self.assertLogRevnos(['file4', 'dir1/dir2'], ['4', '3'])
1069
self.assertRevnos('file4 dir1/dir2', ['4', '3'])
968
1071
def test_log_files_and_dirs_in_nested_directory(self):
969
1072
"""The log for a directory should show all nested files."""
970
1073
self.prepare_tree()
971
1074
os.chdir("dir1")
972
self.assertLogRevnos(['dir2', 'file5'], ['5', '3'])
975
class MainlineGhostTests(TestLogWithLogCatcher):
978
super(MainlineGhostTests, self).setUp()
979
tree = self.make_branch_and_tree('')
980
tree.set_parent_ids(["spooky"], allow_leftmost_as_ghost=True)
982
tree.commit('msg1', rev_id='rev1')
983
tree.commit('msg2', rev_id='rev2')
985
def test_log_range(self):
986
self.assertLogRevnos(["-r1..2"], ["2", "1"])
988
def test_log_norange(self):
989
self.assertLogRevnos([], ["2", "1"])
991
def test_log_range_open_begin(self):
992
self.knownFailure("log with ghosts fails. bug #726466")
993
(stdout, stderr) = self.run_bzr(['log', '-r..2'], retcode=3)
994
self.assertEqual(["2", "1"],
995
[r.revno for r in self.get_captured_revisions()])
996
self.assertEquals("bzr: ERROR: Further revision history missing.", stderr)
998
def test_log_range_open_end(self):
999
self.assertLogRevnos(["-r1.."], ["2", "1"])
1001
class TestLogMatch(TestLogWithLogCatcher):
1002
def prepare_tree(self):
1003
tree = self.make_branch_and_tree('')
1005
['/hello.txt', '/goodbye.txt'])
1006
tree.add('hello.txt')
1007
tree.commit(message='message1', committer='committer1', authors=['author1'])
1008
tree.add('goodbye.txt')
1009
tree.commit(message='message2', committer='committer2', authors=['author2'])
1011
def test_message(self):
1013
self.assertLogRevnos(["-m", "message1"], ["1"])
1014
self.assertLogRevnos(["-m", "message2"], ["2"])
1015
self.assertLogRevnos(["-m", "message"], ["2", "1"])
1016
self.assertLogRevnos(["-m", "message1", "-m", "message2"], ["2", "1"])
1017
self.assertLogRevnos(["--match-message", "message1"], ["1"])
1018
self.assertLogRevnos(["--match-message", "message2"], ["2"])
1019
self.assertLogRevnos(["--match-message", "message"], ["2", "1"])
1020
self.assertLogRevnos(["--match-message", "message1",
1021
"--match-message", "message2"], ["2", "1"])
1022
self.assertLogRevnos(["--message", "message1"], ["1"])
1023
self.assertLogRevnos(["--message", "message2"], ["2"])
1024
self.assertLogRevnos(["--message", "message"], ["2", "1"])
1025
self.assertLogRevnos(["--match-message", "message1",
1026
"--message", "message2"], ["2", "1"])
1027
self.assertLogRevnos(["--message", "message1",
1028
"--match-message", "message2"], ["2", "1"])
1030
def test_committer(self):
1032
self.assertLogRevnos(["-m", "committer1"], ["1"])
1033
self.assertLogRevnos(["-m", "committer2"], ["2"])
1034
self.assertLogRevnos(["-m", "committer"], ["2", "1"])
1035
self.assertLogRevnos(["-m", "committer1", "-m", "committer2"],
1037
self.assertLogRevnos(["--match-committer", "committer1"], ["1"])
1038
self.assertLogRevnos(["--match-committer", "committer2"], ["2"])
1039
self.assertLogRevnos(["--match-committer", "committer"], ["2", "1"])
1040
self.assertLogRevnos(["--match-committer", "committer1",
1041
"--match-committer", "committer2"], ["2", "1"])
1043
def test_author(self):
1045
self.assertLogRevnos(["-m", "author1"], ["1"])
1046
self.assertLogRevnos(["-m", "author2"], ["2"])
1047
self.assertLogRevnos(["-m", "author"], ["2", "1"])
1048
self.assertLogRevnos(["-m", "author1", "-m", "author2"],
1050
self.assertLogRevnos(["--match-author", "author1"], ["1"])
1051
self.assertLogRevnos(["--match-author", "author2"], ["2"])
1052
self.assertLogRevnos(["--match-author", "author"], ["2", "1"])
1053
self.assertLogRevnos(["--match-author", "author1",
1054
"--match-author", "author2"], ["2", "1"])
1057
class TestSmartServerLog(tests.TestCaseWithTransport):
1059
def test_standard_log(self):
1060
self.setup_smart_server_with_call_log()
1061
t = self.make_branch_and_tree('branch')
1062
self.build_tree_contents([('branch/foo', 'thecontents')])
1065
self.reset_smart_call_log()
1066
out, err = self.run_bzr(['log', self.get_url('branch')])
1067
# This figure represent the amount of work to perform this use case. It
1068
# is entirely ok to reduce this number if a test fails due to rpc_count
1069
# being too low. If rpc_count increases, more network roundtrips have
1070
# become necessary for this use case. Please do not adjust this number
1071
# upwards without agreement from bzr's network support maintainers.
1072
self.assertLength(10, self.hpss_calls)
1074
def test_verbose_log(self):
1075
self.setup_smart_server_with_call_log()
1076
t = self.make_branch_and_tree('branch')
1077
self.build_tree_contents([('branch/foo', 'thecontents')])
1080
self.reset_smart_call_log()
1081
out, err = self.run_bzr(['log', '-v', self.get_url('branch')])
1082
# This figure represent the amount of work to perform this use case. It
1083
# is entirely ok to reduce this number if a test fails due to rpc_count
1084
# being too low. If rpc_count increases, more network roundtrips have
1085
# become necessary for this use case. Please do not adjust this number
1086
# upwards without agreement from bzr's network support maintainers.
1087
self.assertLength(19, self.hpss_calls)
1089
def test_per_file(self):
1090
self.setup_smart_server_with_call_log()
1091
t = self.make_branch_and_tree('branch')
1092
self.build_tree_contents([('branch/foo', 'thecontents')])
1095
self.reset_smart_call_log()
1096
out, err = self.run_bzr(['log', '-v', self.get_url('branch') + "/foo"])
1097
# This figure represent the amount of work to perform this use case. It
1098
# is entirely ok to reduce this number if a test fails due to rpc_count
1099
# being too low. If rpc_count increases, more network roundtrips have
1100
# become necessary for this use case. Please do not adjust this number
1101
# upwards without agreement from bzr's network support maintainers.
1102
self.assertLength(21, self.hpss_calls)
1075
self.assertRevnos('dir2 file5', ['5', '3'])