63
65
tree.commit(message='merge')
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):
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
80
# Break cycle with closure over self on cleanup by removing method
81
self.addCleanup(setattr, MyLogFormatter, "__new__", None)
84
# Always return our own log formatter class hijacking the
85
# default behavior (which requires setting up a config
88
self.overrideAttr(log.log_formatter_registry, 'get_default', getme)
90
def get_captured_revisions(self):
91
return self.log_catcher.revisions
93
def assertLogRevnos(self, args, expected_revnos, working_dir='.',
95
actual_out, actual_err = self.run_bzr(['log'] + args,
96
working_dir=working_dir)
97
self.assertEqual(out, actual_out)
98
self.assertEqual(err, actual_err)
99
self.assertEqual(expected_revnos,
100
[r.revno for r in self.get_captured_revisions()])
102
def assertLogRevnosAndDepths(self, args, expected_revnos_and_depths,
104
self.run_bzr(['log'] + args, working_dir=working_dir)
105
self.assertEqual(expected_revnos_and_depths,
106
[(r.revno, r.merge_depth)
107
for r in self.get_captured_revisions()])
110
class TestLogRevSpecs(TestLogWithLogCatcher):
112
def test_log_no_revspec(self):
113
self.make_linear_branch()
114
self.assertLogRevnos([], ['3', '2', '1'])
96
116
def test_log_null_end_revspec(self):
97
117
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)
106
full_log = self.run_bzr(['log'])[0]
107
log = self.run_bzr("log -r 1..")[0]
108
self.assertEqualDiff(log, full_log)
118
self.assertLogRevnos(['-r1..'], ['3', '2', '1'])
110
120
def test_log_null_begin_revspec(self):
111
121
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)
122
self.assertLogRevnos(['-r..3'], ['3', '2', '1'])
116
124
def test_log_null_both_revspecs(self):
117
125
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)
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.'],
126
self.assertLogRevnos(['-r..'], ['3', '2', '1'])
137
128
def test_log_negative_begin_revspec_full_log(self):
138
129
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)
130
self.assertLogRevnos(['-r-3..'], ['3', '2', '1'])
143
132
def test_log_negative_both_revspec_full_log(self):
144
133
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)
134
self.assertLogRevnos(['-r-3..-1'], ['3', '2', '1'])
149
136
def test_log_negative_both_revspec_partial(self):
150
137
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)
138
self.assertLogRevnos(['-r-3..-2'], ['2', '1'])
156
140
def test_log_negative_begin_revspec(self):
157
141
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)
142
self.assertLogRevnos(['-r-2..'], ['3', '2'])
163
144
def test_log_positive_revspecs(self):
164
145
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)
146
self.assertLogRevnos(['-r1..3'], ['3', '2', '1'])
169
148
def test_log_dotted_revspecs(self):
170
149
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))
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',),
150
self.assertLogRevnos(['-n0', '-r1..1.1.1'], ['1.1.1', '1'])
152
def test_log_limit(self):
153
tree = self.make_branch_and_tree('.')
154
# We want more commits than our batch size starts at
155
for pos in range(10):
156
tree.commit("%s" % pos)
157
self.assertLogRevnos(['--limit', '2'], ['10', '9'])
159
def test_log_limit_short(self):
160
self.make_linear_branch()
161
self.assertLogRevnos(['-l', '2'], ['3', '2'])
163
def test_log_change_revno(self):
164
self.make_linear_branch()
165
self.assertLogRevnos(['-c1'], ['1'])
167
def test_branch_revspec(self):
168
foo = self.make_branch_and_tree('foo')
169
bar = self.make_branch_and_tree('bar')
170
self.build_tree(['foo/foo.txt', 'bar/bar.txt'])
173
foo.commit(message='foo')
174
bar.commit(message='bar')
175
self.run_bzr('log -r branch:../bar', working_dir='foo')
176
self.assertEqual([bar.branch.get_rev_id(1)],
178
for r in self.get_captured_revisions()])
181
class TestLogExcludeCommonAncestry(TestLogWithLogCatcher):
183
def test_exclude_common_ancestry_simple_revnos(self):
184
self.make_linear_branch()
185
self.assertLogRevnos(['-r1..3', '--exclude-common-ancestry'],
189
class TestLogMergedLinearAncestry(TestLogWithLogCatcher):
192
super(TestLogMergedLinearAncestry, self).setUp()
193
# FIXME: Using a MemoryTree would be even better here (but until we
194
# stop calling run_bzr, there is no point) --vila 100118.
195
builder = branchbuilder.BranchBuilder(self.get_transport())
196
builder.start_series()
214
builder.build_snapshot('1', None, [
215
('add', ('', 'root-id', 'directory', ''))])
216
builder.build_snapshot('2', ['1'], [])
218
builder.build_snapshot('1.1.1', ['1'], [])
219
# merge branch into mainline
220
builder.build_snapshot('3', ['2', '1.1.1'], [])
221
# new commits in branch
222
builder.build_snapshot('1.1.2', ['1.1.1'], [])
223
builder.build_snapshot('1.1.3', ['1.1.2'], [])
224
# merge branch into mainline
225
builder.build_snapshot('4', ['3', '1.1.3'], [])
226
# merge mainline into branch
227
builder.build_snapshot('1.1.4', ['1.1.3', '4'], [])
228
# merge branch into mainline
229
builder.build_snapshot('5', ['4', '1.1.4'], [])
230
builder.build_snapshot('5.1.1', ['5'], [])
231
builder.build_snapshot('6', ['5', '5.1.1'], [])
232
builder.finish_series()
235
self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4'],
236
['1.1.4', '4', '1.1.3', '1.1.2', '3', '1.1.1'])
237
def test_n0_forward(self):
238
self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4', '--forward'],
239
['3', '1.1.1', '4', '1.1.2', '1.1.3', '1.1.4'])
242
# starting from 1.1.4 we follow the left-hand ancestry
243
self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4'],
244
['1.1.4', '1.1.3', '1.1.2', '1.1.1'])
246
def test_n1_forward(self):
247
self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4', '--forward'],
248
['1.1.1', '1.1.2', '1.1.3', '1.1.4'])
250
def test_fallback_when_end_rev_is_not_on_mainline(self):
251
self.assertLogRevnos(['-n1', '-r1.1.1..5.1.1'],
252
# We don't get 1.1.1 because we say -n1
253
['5.1.1', '5', '4', '3'])
256
class Test_GenerateAllRevisions(TestLogWithLogCatcher):
259
super(Test_GenerateAllRevisions, self).setUp()
260
builder = self.make_branch_with_many_merges()
261
b = builder.get_branch()
263
self.addCleanup(b.unlock)
266
def make_branch_with_many_merges(self, path='.', format=None):
267
builder = branchbuilder.BranchBuilder(self.get_transport())
268
builder.start_series()
269
# The graph below may look a bit complicated (and it may be but I've
270
# banged my head enough on it) but the bug requires at least dotted
271
# revnos *and* merged revisions below that.
285
builder.build_snapshot('1', None, [
286
('add', ('', 'root-id', 'directory', ''))])
287
builder.build_snapshot('2', ['1'], [])
288
builder.build_snapshot('1.1.1', ['1'], [])
289
builder.build_snapshot('2.1.1', ['2'], [])
290
builder.build_snapshot('3', ['2', '1.1.1'], [])
291
builder.build_snapshot('2.1.2', ['2.1.1'], [])
292
builder.build_snapshot('2.2.1', ['2.1.1'], [])
293
builder.build_snapshot('2.1.3', ['2.1.2', '2.2.1'], [])
294
builder.build_snapshot('4', ['3', '2.1.3'], [])
295
builder.build_snapshot('5', ['4', '2.1.2'], [])
296
builder.finish_series()
299
def test_not_an_ancestor(self):
300
self.assertRaises(errors.BzrCommandError,
301
log._generate_all_revisions,
302
self.branch, '1.1.1', '2.1.3', 'reverse',
303
delayed_graph_generation=True)
305
def test_wrong_order(self):
306
self.assertRaises(errors.BzrCommandError,
307
log._generate_all_revisions,
308
self.branch, '5', '2.1.3', 'reverse',
309
delayed_graph_generation=True)
311
def test_no_start_rev_id_with_end_rev_id_being_a_merge(self):
312
revs = log._generate_all_revisions(
313
self.branch, None, '2.1.3',
314
'reverse', delayed_graph_generation=True)
317
class TestLogRevSpecsWithPaths(TestLogWithLogCatcher):
319
def test_log_revno_n_path_wrong_namespace(self):
320
self.make_linear_branch('branch1')
321
self.make_linear_branch('branch2')
322
# There is no guarantee that a path exist between two arbitrary
324
self.run_bzr("log -r revno:2:branch1..revno:3:branch2", retcode=3)
326
def test_log_revno_n_path_correct_order(self):
327
self.make_linear_branch('branch2')
328
self.assertLogRevnos(['-rrevno:1:branch2..revno:3:branch2'],
186
331
def test_log_revno_n_path(self):
187
self.make_linear_branch('branch1')
188
332
self.make_linear_branch('branch2')
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)
333
self.assertLogRevnos(['-rrevno:1:branch2'],
335
rev_props = self.log_catcher.revisions[0].rev.properties
336
self.assertEqual('branch2', rev_props['branch-nick'])
339
class TestLogErrors(TestLog):
341
def test_log_zero_revspec(self):
342
self.make_minimal_branch()
343
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
346
def test_log_zero_begin_revspec(self):
347
self.make_linear_branch()
348
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
351
def test_log_zero_end_revspec(self):
352
self.make_linear_branch()
353
self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
201
356
def test_log_nonexistent_revno(self):
202
357
self.make_minimal_branch()
203
(out, err) = self.run_bzr_error(
204
["bzr: ERROR: Requested revision: '1234' "
205
"does not exist in branch:"],
358
self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
359
"does not exist in branch:"],
208
362
def test_log_nonexistent_dotted_revno(self):
209
363
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'])
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)
364
self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
365
"does not exist in branch:"],
366
['log', '-r123.123'])
221
368
def test_log_change_nonexistent_revno(self):
222
369
self.make_minimal_branch()
223
(out, err) = self.run_bzr_error(
224
["bzr: ERROR: Requested revision: '1234' "
225
"does not exist in branch:"],
370
self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
371
"does not exist in branch:"],
228
374
def test_log_change_nonexistent_dotted_revno(self):
229
375
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'])
376
self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
377
"does not exist in branch:"],
378
['log', '-c123.123'])
235
380
def test_log_change_single_revno_only(self):
236
381
self.make_minimal_branch()
373
538
def make_branches_with_merges(self):
374
539
level0 = self.make_branch_and_tree('level0')
375
level0.commit(message='in branch level0', **self.commit_options())
540
self.wt_commit(level0, 'in branch level0')
377
541
level1 = level0.bzrdir.sprout('level1').open_workingtree()
378
level1.commit(message='in branch level1', **self.commit_options())
542
self.wt_commit(level1, 'in branch level1')
380
543
level2 = level1.bzrdir.sprout('level2').open_workingtree()
381
level2.commit(message='in branch level2', **self.commit_options())
544
self.wt_commit(level2, 'in branch level2')
383
545
level1.merge_from_branch(level2.branch)
384
level1.commit(message='merge branch level2', **self.commit_options())
546
self.wt_commit(level1, 'merge branch level2')
386
547
level0.merge_from_branch(level1.branch)
387
level0.commit(message='merge branch level1', **self.commit_options())
548
self.wt_commit(level0, 'merge branch level1')
389
550
def test_merges_are_indented_by_level(self):
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'])
551
self.run_bzr(['log', '-n0'], working_dir='level0')
552
revnos_and_depth = [(r.revno, r.merge_depth)
553
for r in self.get_captured_revisions()]
554
self.assertEqual([('2', 0), ('1.1.2', 1), ('1.2.1', 2), ('1.1.1', 1),
556
[(r.revno, r.merge_depth)
557
for r in self.get_captured_revisions()])
429
559
def test_force_merge_revisions_off(self):
431
------------------------------------------------------------
433
committer: Lorem Ipsum <test@example.com>
438
------------------------------------------------------------
440
committer: Lorem Ipsum <test@example.com>
446
self.check_log(expected, ['--long', '-n1'])
560
self.assertLogRevnos(['-n1'], ['2', '1'], working_dir='level0')
448
562
def test_force_merge_revisions_on(self):
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'])
563
self.assertLogRevnos(['-n0'], ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
564
working_dir='level0')
468
566
def test_include_merges(self):
469
567
# Confirm --include-merges gives the same output as -n0
568
msg = ("The option '--include-merges' to 'bzr log' "
569
"has been deprecated in bzr 2.5. "
570
"Please use '--include-merged' instead.\n")
571
self.assertLogRevnos(['--include-merges'],
572
['2', '1.1.2', '1.2.1', '1.1.1', '1'],
573
working_dir='level0', err=msg)
574
self.assertLogRevnos(['--include-merges'],
575
['2', '1.1.2', '1.2.1', '1.1.1', '1'],
576
working_dir='level0', err=msg)
470
577
out_im, err_im = self.run_bzr('log --include-merges',
471
578
working_dir='level0')
472
579
out_n0, err_n0 = self.run_bzr('log -n0', working_dir='level0')
473
self.assertEqual('', err_im)
580
self.assertEqual(msg, err_im)
474
581
self.assertEqual('', err_n0)
475
582
self.assertEqual(out_im, out_n0)
584
def test_include_merged(self):
585
# Confirm --include-merged gives the same output as -n0
586
expected = ['2', '1.1.2', '1.2.1', '1.1.1', '1']
587
self.assertLogRevnos(['--include-merged'],
588
expected, working_dir='level0')
589
self.assertLogRevnos(['--include-merged'],
590
expected, working_dir='level0')
477
592
def test_force_merge_revisions_N(self):
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'])
593
self.assertLogRevnos(['-n2'],
594
['2', '1.1.2', '1.1.1', '1'],
595
working_dir='level0')
494
597
def test_merges_single_merge_rev(self):
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'])
598
self.assertLogRevnosAndDepths(['-n0', '-r1.1.2'],
599
[('1.1.2', 0), ('1.2.1', 1)],
600
working_dir='level0')
513
602
def test_merges_partial_range(self):
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'])
603
self.assertLogRevnosAndDepths(
604
['-n0', '-r1.1.1..1.1.2'],
605
[('1.1.2', 0), ('1.2.1', 1), ('1.1.1', 0)],
606
working_dir='level0')
539
608
def test_merges_partial_range_ignore_before_lower_bound(self):
540
609
"""Dont show revisions before the lower bound's merged revs"""
542
2 Lorem Ipsum\t2005-11-22 [merge]
545
1.1.2 Lorem Ipsum\t2005-11-22 [merge]
548
1.2.1 Lorem Ipsum\t2005-11-22
552
self.check_log(expected, ['--short', '-n0', '-r1.1.2..2'])
555
class TestLogDiff(TestLog):
610
self.assertLogRevnosAndDepths(
611
['-n0', '-r1.1.2..2'],
612
[('2', 0), ('1.1.2', 1), ('1.2.1', 2)],
613
working_dir='level0')
615
def test_omit_merges_with_sidelines(self):
616
self.assertLogRevnos(['--omit-merges', '-n0'], ['1.2.1', '1.1.1', '1'],
617
working_dir='level0')
619
def test_omit_merges_without_sidelines(self):
620
self.assertLogRevnos(['--omit-merges', '-n1'], ['1'],
621
working_dir='level0')
624
class TestLogDiff(TestLogWithLogCatcher):
626
# FIXME: We need specific tests for each LogFormatter about how the diffs
627
# are displayed: --long indent them by depth, --short use a fixed
628
# indent and --line does't display them. -- vila 10019
558
631
super(TestLogDiff, self).setUp()
563
636
self.build_tree(['level0/file1', 'level0/file2'])
564
637
level0.add('file1')
565
638
level0.add('file2')
566
level0.commit(message='in branch level0', **self.commit_options())
639
self.wt_commit(level0, 'in branch level0')
568
641
level1 = level0.bzrdir.sprout('level1').open_workingtree()
569
642
self.build_tree_contents([('level1/file2', 'hello\n')])
570
level1.commit(message='in branch level1', **self.commit_options())
643
self.wt_commit(level1, 'in branch level1')
571
644
level0.merge_from_branch(level1.branch)
572
level0.commit(message='merge branch level1', **self.commit_options())
645
self.wt_commit(level0, 'merge branch level1')
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)
579
------------------------------------------------------------
581
committer: Lorem Ipsum <test@example.com>
587
=== modified file 'file2'
588
--- file2\t2005-11-22 00:00:01 +0000
589
+++ file2\t2005-11-22 00:00:02 +0000
591
-contents of level0/file2
593
------------------------------------------------------------
595
committer: Lorem Ipsum <test@example.com>
601
=== modified file 'file2'
602
--- file2\t2005-11-22 00:00:01 +0000
603
+++ file2\t2005-11-22 00:00:02 +0000
605
-contents of level0/file2
607
------------------------------------------------------------
609
committer: Lorem Ipsum <test@example.com>
615
=== added file 'file1'
647
def _diff_file1_revno1(self):
648
return """=== added file 'file1'
616
649
--- file1\t1970-01-01 00:00:00 +0000
617
+++ file1\t2005-11-22 00:00:01 +0000
650
+++ file1\t2005-11-22 00:00:00 +0000
619
652
+contents of level0/file1
621
=== added file 'file2'
656
def _diff_file2_revno2(self):
657
return """=== modified file 'file2'
658
--- file2\t2005-11-22 00:00:00 +0000
659
+++ file2\t2005-11-22 00:00:01 +0000
661
-contents of level0/file2
666
def _diff_file2_revno1_1_1(self):
667
return """=== modified file 'file2'
668
--- file2\t2005-11-22 00:00:00 +0000
669
+++ file2\t2005-11-22 00:00:01 +0000
671
-contents of level0/file2
676
def _diff_file2_revno1(self):
677
return """=== added file 'file2'
622
678
--- file2\t1970-01-01 00:00:00 +0000
623
+++ file2\t2005-11-22 00:00:01 +0000
679
+++ file2\t2005-11-22 00:00:00 +0000
625
681
+contents of level0/file2
627
self.check_log(expected, ['-p', '-n0'])
629
def test_log_show_diff_short(self):
631
2 Lorem Ipsum\t2005-11-22 [merge]
633
=== modified file 'file2'
634
--- file2\t2005-11-22 00:00:01 +0000
635
+++ file2\t2005-11-22 00:00:02 +0000
637
-contents of level0/file2
640
1 Lorem Ipsum\t2005-11-22
642
=== added file 'file1'
643
--- file1\t1970-01-01 00:00:00 +0000
644
+++ file1\t2005-11-22 00:00:01 +0000
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
652
+contents of level0/file2
654
Use --include-merges or -n0 to see merged revisions.
656
self.check_log(expected, ['-p', '--short'])
658
def test_log_show_diff_line(self):
659
# Not supported by this formatter so expect plain output
661
2: Lorem Ipsum 2005-11-22 [merge] merge branch level1
662
1: Lorem Ipsum 2005-11-22 in branch level0
664
self.check_log(expected, ['-p', '--line'])
666
def test_log_show_diff_file1(self):
667
"""Only the diffs for the given file are to be shown"""
669
1 Lorem Ipsum\t2005-11-22
671
=== added file 'file1'
672
--- file1\t1970-01-01 00:00:00 +0000
673
+++ file1\t2005-11-22 00:00:01 +0000
675
+contents of level0/file1
678
self.check_log(expected, ['-p', '--short', 'file1'])
680
def test_log_show_diff_file2(self):
681
"""Only the diffs for the given file are to be shown"""
683
2 Lorem Ipsum\t2005-11-22 [merge]
685
=== modified file 'file2'
686
--- file2\t2005-11-22 00:00:01 +0000
687
+++ file2\t2005-11-22 00:00:02 +0000
689
-contents of level0/file2
692
1 Lorem Ipsum\t2005-11-22
694
=== added file 'file2'
695
--- file2\t1970-01-01 00:00:00 +0000
696
+++ file2\t2005-11-22 00:00:01 +0000
698
+contents of level0/file2
700
Use --include-merges or -n0 to see merged revisions.
702
self.check_log(expected, ['-p', '--short', 'file2'])
685
def assertLogRevnosAndDiff(self, args, expected,
687
self.run_bzr(['log', '-p'] + args, working_dir=working_dir)
688
expected_revnos_and_depths = [
689
(revno, depth) for revno, depth, diff in expected]
690
# Check the revnos and depths first to make debugging easier
691
self.assertEqual(expected_revnos_and_depths,
692
[(r.revno, r.merge_depth)
693
for r in self.get_captured_revisions()])
694
# Now check the diffs, adding the revno in case of failure
695
fmt = 'In revno %s\n%s'
696
for expected_rev, actual_rev in izip(expected,
697
self.get_captured_revisions()):
698
revno, depth, expected_diff = expected_rev
699
actual_diff = actual_rev.diff
700
self.assertEqualDiff(fmt % (revno, expected_diff),
701
fmt % (revno, actual_diff))
703
def test_log_diff_with_merges(self):
704
self.assertLogRevnosAndDiff(
706
[('2', 0, self._diff_file2_revno2()),
707
('1.1.1', 1, self._diff_file2_revno1_1_1()),
708
('1', 0, self._diff_file1_revno1()
709
+ self._diff_file2_revno1())],
710
working_dir='level0')
713
def test_log_diff_file1(self):
714
self.assertLogRevnosAndDiff(['-n0', 'file1'],
715
[('1', 0, self._diff_file1_revno1())],
716
working_dir='level0')
718
def test_log_diff_file2(self):
719
self.assertLogRevnosAndDiff(['-n1', 'file2'],
720
[('2', 0, self._diff_file2_revno2()),
721
('1', 0, self._diff_file2_revno1())],
722
working_dir='level0')
705
725
class TestLogUnicodeDiff(TestLog):
860
877
tree.commit('remove file1')
861
878
os.chdir('parent')
863
def test_log_file(self):
864
"""The log for a particular file should only list revs for that file"""
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 ')
880
# FIXME: It would be good to parametrize the following tests against all
881
# formatters. But the revisions selection is not *currently* part of the
882
# LogFormatter contract, so using LogCatcher is sufficient -- vila 100118
883
def test_log_file1(self):
885
self.assertLogRevnos(['-n0', 'file1'], ['1'])
887
def test_log_file2(self):
890
self.assertLogRevnos(['-n0', 'file2'], ['4', '3.1.1', '2'])
891
# file2 in a merge revision
892
self.assertLogRevnos(['-n0', '-r3.1.1', 'file2'], ['3.1.1'])
893
# file2 in a mainline revision
894
self.assertLogRevnos(['-n0', '-r4', 'file2'], ['4', '3.1.1'])
895
# file2 since a revision
896
self.assertLogRevnos(['-n0', '-r3..', 'file2'], ['4', '3.1.1'])
897
# file2 up to a revision
898
self.assertLogRevnos(['-n0', '-r..3', 'file2'], ['2'])
900
def test_log_file3(self):
902
self.assertLogRevnos(['-n0', 'file3'], ['3'])
909
904
def test_log_file_historical_missing(self):
910
905
# Check logging a deleted file gives an error if the
948
931
self.assertContainsRe(err, err_msg)
950
933
# 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 ')
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.
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)
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)
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)
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)
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)
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)
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)
1023
class TestLogMultiple(tests.TestCaseWithTransport):
934
self.assertLogRevnos(['-r..4', 'file3'], ['3'])
937
class TestLogMultiple(TestLogWithLogCatcher):
1025
939
def prepare_tree(self):
1026
940
tree = self.make_branch_and_tree('parent')
1049
963
tree.commit(message='merge child branch')
1050
964
os.chdir('parent')
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)
1059
966
def test_log_files(self):
1060
967
"""The log for multiple file should only list revs for those files"""
1061
968
self.prepare_tree()
1062
self.assertRevnos('file1 file2 dir1/dir2/file3',
1063
['6', '5.1.1', '3', '2', '1'])
969
self.assertLogRevnos(['file1', 'file2', 'dir1/dir2/file3'],
970
['6', '5.1.1', '3', '2', '1'])
1065
972
def test_log_directory(self):
1066
973
"""The log for a directory should show all nested files."""
1067
974
self.prepare_tree()
1068
self.assertRevnos('dir1', ['5', '3'])
975
self.assertLogRevnos(['dir1'], ['5', '3'])
1070
977
def test_log_nested_directory(self):
1071
978
"""The log for a directory should show all nested files."""
1072
979
self.prepare_tree()
1073
self.assertRevnos('dir1/dir2', ['3'])
980
self.assertLogRevnos(['dir1/dir2'], ['3'])
1075
982
def test_log_in_nested_directory(self):
1076
983
"""The log for a directory should show all nested files."""
1077
984
self.prepare_tree()
1078
985
os.chdir("dir1")
1079
self.assertRevnos('.', ['5', '3'])
986
self.assertLogRevnos(['.'], ['5', '3'])
1081
988
def test_log_files_and_directories(self):
1082
989
"""Logging files and directories together should be fine."""
1083
990
self.prepare_tree()
1084
self.assertRevnos('file4 dir1/dir2', ['4', '3'])
991
self.assertLogRevnos(['file4', 'dir1/dir2'], ['4', '3'])
1086
993
def test_log_files_and_dirs_in_nested_directory(self):
1087
994
"""The log for a directory should show all nested files."""
1088
995
self.prepare_tree()
1089
996
os.chdir("dir1")
1090
self.assertRevnos('dir2 file5', ['5', '3'])
997
self.assertLogRevnos(['dir2', 'file5'], ['5', '3'])
1000
class MainlineGhostTests(TestLogWithLogCatcher):
1003
super(MainlineGhostTests, self).setUp()
1004
tree = self.make_branch_and_tree('')
1005
tree.set_parent_ids(["spooky"], allow_leftmost_as_ghost=True)
1007
tree.commit('msg1', rev_id='rev1')
1008
tree.commit('msg2', rev_id='rev2')
1010
def test_log_range(self):
1011
self.assertLogRevnos(["-r1..2"], ["2", "1"])
1013
def test_log_norange(self):
1014
self.assertLogRevnos([], ["2", "1"])
1016
def test_log_range_open_begin(self):
1017
self.knownFailure("log with ghosts fails. bug #726466")
1018
(stdout, stderr) = self.run_bzr(['log', '-r..2'], retcode=3)
1019
self.assertEqual(["2", "1"],
1020
[r.revno for r in self.get_captured_revisions()])
1021
self.assertEquals("bzr: ERROR: Further revision history missing.", stderr)
1023
def test_log_range_open_end(self):
1024
self.assertLogRevnos(["-r1.."], ["2", "1"])
1026
class TestLogMatch(TestLogWithLogCatcher):
1027
def prepare_tree(self):
1028
tree = self.make_branch_and_tree('')
1030
['/hello.txt', '/goodbye.txt'])
1031
tree.add('hello.txt')
1032
tree.commit(message='message1', committer='committer1', authors=['author1'])
1033
tree.add('goodbye.txt')
1034
tree.commit(message='message2', committer='committer2', authors=['author2'])
1036
def test_message(self):
1038
self.assertLogRevnos(["-m", "message1"], ["1"])
1039
self.assertLogRevnos(["-m", "message2"], ["2"])
1040
self.assertLogRevnos(["-m", "message"], ["2", "1"])
1041
self.assertLogRevnos(["-m", "message1", "-m", "message2"], ["2", "1"])
1042
self.assertLogRevnos(["--match-message", "message1"], ["1"])
1043
self.assertLogRevnos(["--match-message", "message2"], ["2"])
1044
self.assertLogRevnos(["--match-message", "message"], ["2", "1"])
1045
self.assertLogRevnos(["--match-message", "message1",
1046
"--match-message", "message2"], ["2", "1"])
1047
self.assertLogRevnos(["--message", "message1"], ["1"])
1048
self.assertLogRevnos(["--message", "message2"], ["2"])
1049
self.assertLogRevnos(["--message", "message"], ["2", "1"])
1050
self.assertLogRevnos(["--match-message", "message1",
1051
"--message", "message2"], ["2", "1"])
1052
self.assertLogRevnos(["--message", "message1",
1053
"--match-message", "message2"], ["2", "1"])
1055
def test_committer(self):
1057
self.assertLogRevnos(["-m", "committer1"], ["1"])
1058
self.assertLogRevnos(["-m", "committer2"], ["2"])
1059
self.assertLogRevnos(["-m", "committer"], ["2", "1"])
1060
self.assertLogRevnos(["-m", "committer1", "-m", "committer2"],
1062
self.assertLogRevnos(["--match-committer", "committer1"], ["1"])
1063
self.assertLogRevnos(["--match-committer", "committer2"], ["2"])
1064
self.assertLogRevnos(["--match-committer", "committer"], ["2", "1"])
1065
self.assertLogRevnos(["--match-committer", "committer1",
1066
"--match-committer", "committer2"], ["2", "1"])
1068
def test_author(self):
1070
self.assertLogRevnos(["-m", "author1"], ["1"])
1071
self.assertLogRevnos(["-m", "author2"], ["2"])
1072
self.assertLogRevnos(["-m", "author"], ["2", "1"])
1073
self.assertLogRevnos(["-m", "author1", "-m", "author2"],
1075
self.assertLogRevnos(["--match-author", "author1"], ["1"])
1076
self.assertLogRevnos(["--match-author", "author2"], ["2"])
1077
self.assertLogRevnos(["--match-author", "author"], ["2", "1"])
1078
self.assertLogRevnos(["--match-author", "author1",
1079
"--match-author", "author2"], ["2", "1"])
1082
class TestSmartServerLog(tests.TestCaseWithTransport):
1084
def test_standard_log(self):
1085
self.setup_smart_server_with_call_log()
1086
t = self.make_branch_and_tree('branch')
1087
self.build_tree_contents([('branch/foo', 'thecontents')])
1090
self.reset_smart_call_log()
1091
out, err = self.run_bzr(['log', self.get_url('branch')])
1092
# This figure represent the amount of work to perform this use case. It
1093
# is entirely ok to reduce this number if a test fails due to rpc_count
1094
# being too low. If rpc_count increases, more network roundtrips have
1095
# become necessary for this use case. Please do not adjust this number
1096
# upwards without agreement from bzr's network support maintainers.
1097
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
1098
self.assertLength(1, self.hpss_connections)
1099
self.assertLength(9, self.hpss_calls)
1101
def test_verbose_log(self):
1102
self.setup_smart_server_with_call_log()
1103
t = self.make_branch_and_tree('branch')
1104
self.build_tree_contents([('branch/foo', 'thecontents')])
1107
self.reset_smart_call_log()
1108
out, err = self.run_bzr(['log', '-v', self.get_url('branch')])
1109
# This figure represent the amount of work to perform this use case. It
1110
# is entirely ok to reduce this number if a test fails due to rpc_count
1111
# being too low. If rpc_count increases, more network roundtrips have
1112
# become necessary for this use case. Please do not adjust this number
1113
# upwards without agreement from bzr's network support maintainers.
1114
self.assertLength(10, self.hpss_calls)
1115
self.assertLength(1, self.hpss_connections)
1116
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)
1118
def test_per_file(self):
1119
self.setup_smart_server_with_call_log()
1120
t = self.make_branch_and_tree('branch')
1121
self.build_tree_contents([('branch/foo', 'thecontents')])
1124
self.reset_smart_call_log()
1125
out, err = self.run_bzr(['log', '-v', self.get_url('branch') + "/foo"])
1126
# This figure represent the amount of work to perform this use case. It
1127
# is entirely ok to reduce this number if a test fails due to rpc_count
1128
# being too low. If rpc_count increases, more network roundtrips have
1129
# become necessary for this use case. Please do not adjust this number
1130
# upwards without agreement from bzr's network support maintainers.
1131
self.assertLength(14, self.hpss_calls)
1132
self.assertLength(1, self.hpss_connections)
1133
self.assertThat(self.hpss_calls, ContainsNoVfsCalls)