13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
18
from cStringIO import StringIO
32
class TestLogMixin(object):
34
def wt_commit(self, wt, message, **kwargs):
35
"""Use some mostly fixed values for commits to simplify tests.
37
Tests can use this function to get some commit attributes. The time
38
stamp is incremented at each commit.
40
if getattr(self, 'timestamp', None) is None:
41
self.timestamp = 1132617600 # Mon 2005-11-22 00:00:00 +0000
43
self.timestamp += 1 # 1 second between each commit
44
kwargs.setdefault('timestamp', self.timestamp)
45
kwargs.setdefault('timezone', 0) # UTC
46
kwargs.setdefault('committer', 'Joe Foo <joe@foo.com>')
48
return wt.commit(message, **kwargs)
51
class TestCaseForLogFormatter(tests.TestCaseWithTransport, TestLogMixin):
54
super(TestCaseForLogFormatter, self).setUp()
55
# keep a reference to the "current" custom prop. handler registry
56
self.properties_handler_registry = log.properties_handler_registry
57
# Use a clean registry for log
58
log.properties_handler_registry = registry.Registry()
61
log.properties_handler_registry = self.properties_handler_registry
62
self.addCleanup(restore)
64
def assertFormatterResult(self, result, branch, formatter_class,
65
formatter_kwargs=None, show_log_kwargs=None):
66
logfile = self.make_utf8_encoded_stringio()
67
if formatter_kwargs is None:
69
formatter = formatter_class(to_file=logfile, **formatter_kwargs)
70
if show_log_kwargs is None:
72
log.show_log(branch, formatter, **show_log_kwargs)
73
self.assertEqualDiff(result, logfile.getvalue())
75
def make_standard_commit(self, branch_nick, **kwargs):
76
wt = self.make_branch_and_tree('.')
78
self.addCleanup(wt.unlock)
79
self.build_tree(['a'])
81
wt.branch.nick = branch_nick
82
kwargs.setdefault('committer', 'Lorem Ipsum <test@example.com>')
83
kwargs.setdefault('authors', ['John Doe <jdoe@example.com>'])
84
self.wt_commit(wt, 'add a', **kwargs)
87
def make_commits_with_trailing_newlines(self, wt):
88
"""Helper method for LogFormatter tests"""
91
self.build_tree_contents([('a', 'hello moto\n')])
92
self.wt_commit(wt, 'simple log message', rev_id='a1')
93
self.build_tree_contents([('b', 'goodbye\n')])
95
self.wt_commit(wt, 'multiline\nlog\nmessage\n', rev_id='a2')
97
self.build_tree_contents([('c', 'just another manic monday\n')])
99
self.wt_commit(wt, 'single line with trailing newline\n', rev_id='a3')
102
def _prepare_tree_with_merges(self, with_tags=False):
103
wt = self.make_branch_and_memory_tree('.')
105
self.addCleanup(wt.unlock)
107
self.wt_commit(wt, 'rev-1', rev_id='rev-1')
108
self.wt_commit(wt, 'rev-merged', rev_id='rev-2a')
109
wt.set_parent_ids(['rev-1', 'rev-2a'])
110
wt.branch.set_last_revision_info(1, 'rev-1')
111
self.wt_commit(wt, 'rev-2', rev_id='rev-2b')
114
branch.tags.set_tag('v0.2', 'rev-2b')
115
self.wt_commit(wt, 'rev-3', rev_id='rev-3')
116
branch.tags.set_tag('v1.0rc1', 'rev-3')
117
branch.tags.set_tag('v1.0', 'rev-3')
121
class LogCatcher(log.LogFormatter):
122
"""Pull log messages into a list rather than displaying them.
124
To simplify testing we save logged revisions here rather than actually
125
formatting anything, so that we can precisely check the result without
126
being dependent on the formatting.
20
from bzrlib import log
21
from bzrlib.tests import TestCaseWithTransport
22
from bzrlib.log import (show_log,
29
from bzrlib.branch import Branch
30
from bzrlib.errors import InvalidRevisionNumber
33
class LogCatcher(LogFormatter):
34
"""Pull log messages into list rather than displaying them.
36
For ease of testing we save log messages here rather than actually
37
formatting them, so that we can precisely check the result without
38
being too dependent on the exact formatting.
40
We should also test the LogFormatter.
129
supports_merge_revisions = True
130
43
supports_delta = True
134
def __init__(self, *args, **kwargs):
135
kwargs.update(dict(to_file=None))
136
super(LogCatcher, self).__init__(*args, **kwargs)
46
super(LogCatcher, self).__init__(to_file=None)
139
49
def log_revision(self, revision):
140
self.revisions.append(revision)
143
class TestShowLog(tests.TestCaseWithTransport):
50
self.logs.append(revision)
53
class TestShowLog(TestCaseWithTransport):
145
55
def checkDelta(self, delta, **kw):
146
"""Check the filenames touched by a delta are as expected.
148
Caller only have to pass in the list of files for each part, all
149
unspecified parts are considered empty (and checked as such).
56
"""Check the filenames touched by a delta are as expected."""
151
57
for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
152
# By default we expect an empty list
153
58
expected = kw.get(n, [])
154
59
# strip out only the path components
155
60
got = [x[0] for x in getattr(delta, n)]
156
self.assertEqual(expected, got)
158
def assertInvalidRevisonNumber(self, br, start, end):
160
self.assertRaises(errors.InvalidRevisionNumber,
161
log.show_log, br, lf,
162
start_revision=start, end_revision=end)
61
self.assertEquals(expected, got)
164
63
def test_cur_revno(self):
165
64
wt = self.make_branch_and_tree('.')
169
68
wt.commit('empty commit')
170
log.show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
172
# Since there is a single revision in the branch all the combinations
174
self.assertInvalidRevisonNumber(b, 2, 1)
175
self.assertInvalidRevisonNumber(b, 1, 2)
176
self.assertInvalidRevisonNumber(b, 0, 2)
177
self.assertInvalidRevisonNumber(b, 1, 0)
178
self.assertInvalidRevisonNumber(b, -1, 1)
179
self.assertInvalidRevisonNumber(b, 1, -1)
181
def test_empty_branch(self):
69
show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
70
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
71
start_revision=2, end_revision=1)
72
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
73
start_revision=1, end_revision=2)
74
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
75
start_revision=0, end_revision=2)
76
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
77
start_revision=1, end_revision=0)
78
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
79
start_revision=-1, end_revision=1)
80
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
81
start_revision=1, end_revision=-1)
83
def test_simple_log(self):
84
eq = self.assertEquals
182
86
wt = self.make_branch_and_tree('.')
185
log.show_log(wt.branch, lf)
187
self.assertEqual([], lf.revisions)
189
def test_empty_commit(self):
190
wt = self.make_branch_and_tree('.')
192
94
wt.commit('empty commit')
194
log.show_log(wt.branch, lf, verbose=True)
196
self.assertEqual(1, len(revs))
197
self.assertEqual('1', revs[0].revno)
198
self.assertEqual('empty commit', revs[0].rev.message)
199
self.checkDelta(revs[0].delta)
96
show_log(b, lf, verbose=True)
98
eq(lf.logs[0].revno, '1')
99
eq(lf.logs[0].rev.message, 'empty commit')
101
self.log('log delta: %r' % d)
201
def test_simple_commit(self):
202
wt = self.make_branch_and_tree('.')
203
wt.commit('empty commit')
204
104
self.build_tree(['hello'])
206
wt.commit('add one file',
207
committer=u'\u013d\xf3r\xe9m \xcdp\u0161\xfam '
208
u'<test@example.com>')
106
wt.commit('add one file')
109
# log using regular thing
110
show_log(b, LongLogFormatter(lf))
112
for l in lf.readlines():
115
# get log as data structure
209
116
lf = LogCatcher()
210
log.show_log(wt.branch, lf, verbose=True)
211
self.assertEqual(2, len(lf.revisions))
117
show_log(b, lf, verbose=True)
119
self.log('log entries:')
120
for logentry in lf.logs:
121
self.log('%4s %s' % (logentry.revno, logentry.rev.message))
212
123
# first one is most recent
213
log_entry = lf.revisions[0]
214
self.assertEqual('2', log_entry.revno)
215
self.assertEqual('add one file', log_entry.rev.message)
216
self.checkDelta(log_entry.delta, added=['hello'])
218
def test_commit_message_with_control_chars(self):
219
wt = self.make_branch_and_tree('.')
220
msg = u"All 8-bit chars: " + ''.join([unichr(x) for x in range(256)])
221
msg = msg.replace(u'\r', u'\n')
124
logentry = lf.logs[0]
125
eq(logentry.revno, '2')
126
eq(logentry.rev.message, 'add one file')
128
self.log('log 2 delta: %r' % d)
129
self.checkDelta(d, added=['hello'])
131
# commit a log message with control characters
132
msg = "All 8-bit chars: " + ''.join([unichr(x) for x in range(256)])
133
self.log("original commit message: %r", msg)
223
135
lf = LogCatcher()
224
log.show_log(wt.branch, lf, verbose=True)
225
committed_msg = lf.revisions[0].rev.message
226
if wt.branch.repository._serializer.squashes_xml_invalid_characters:
227
self.assertNotEqual(msg, committed_msg)
228
self.assertTrue(len(committed_msg) > len(msg))
230
self.assertEqual(msg, committed_msg)
136
show_log(b, lf, verbose=True)
137
committed_msg = lf.logs[0].rev.message
138
self.log("escaped commit message: %r", committed_msg)
139
self.assert_(msg != committed_msg)
140
self.assert_(len(committed_msg) > len(msg))
232
def test_commit_message_without_control_chars(self):
233
wt = self.make_branch_and_tree('.')
142
# Check that log message with only XML-valid characters isn't
234
143
# escaped. As ElementTree apparently does some kind of
235
144
# newline conversion, neither LF (\x0A) nor CR (\x0D) are
236
145
# included in the test commit message, even though they are
237
146
# valid XML 1.0 characters.
238
147
msg = "\x09" + ''.join([unichr(x) for x in range(0x20, 256)])
148
self.log("original commit message: %r", msg)
240
150
lf = LogCatcher()
241
log.show_log(wt.branch, lf, verbose=True)
242
committed_msg = lf.revisions[0].rev.message
243
self.assertEqual(msg, committed_msg)
151
show_log(b, lf, verbose=True)
152
committed_msg = lf.logs[0].rev.message
153
self.log("escaped commit message: %r", committed_msg)
154
self.assert_(msg == committed_msg)
245
156
def test_deltas_in_merge_revisions(self):
246
157
"""Check deltas created for both mainline and merge revisions"""
158
eq = self.assertEquals
247
159
wt = self.make_branch_and_tree('parent')
248
160
self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
262
174
lf = LogCatcher()
263
175
lf.supports_merge_revisions = True
264
log.show_log(b, lf, verbose=True)
267
self.assertEqual(3, len(revs))
270
self.assertEqual('2', logentry.revno)
271
self.assertEqual('merge child branch', logentry.rev.message)
272
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
275
self.assertEqual('1.1.1', logentry.revno)
276
self.assertEqual('remove file1 and modify file2', logentry.rev.message)
277
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
280
self.assertEqual('1', logentry.revno)
281
self.assertEqual('add file1 and file2', logentry.rev.message)
282
self.checkDelta(logentry.delta, added=['file1', 'file2'])
285
class TestShortLogFormatter(TestCaseForLogFormatter):
176
show_log(b, lf, verbose=True)
178
logentry = lf.logs[0]
179
eq(logentry.revno, '2')
180
eq(logentry.rev.message, 'merge child branch')
182
self.checkDelta(d, removed=['file1'], modified=['file2'])
183
logentry = lf.logs[1]
184
eq(logentry.revno, '1.1.1')
185
eq(logentry.rev.message, 'remove file1 and modify file2')
187
self.checkDelta(d, removed=['file1'], modified=['file2'])
188
logentry = lf.logs[2]
189
eq(logentry.revno, '1')
190
eq(logentry.rev.message, 'add file1 and file2')
192
self.checkDelta(d, added=['file1', 'file2'])
195
def make_commits_with_trailing_newlines(wt):
196
"""Helper method for LogFormatter tests"""
199
open('a', 'wb').write('hello moto\n')
201
wt.commit('simple log message', rev_id='a1'
202
, timestamp=1132586655.459960938, timezone=-6*3600
203
, committer='Joe Foo <joe@foo.com>')
204
open('b', 'wb').write('goodbye\n')
206
wt.commit('multiline\nlog\nmessage\n', rev_id='a2'
207
, timestamp=1132586842.411175966, timezone=-6*3600
208
, committer='Joe Foo <joe@foo.com>')
210
open('c', 'wb').write('just another manic monday\n')
212
wt.commit('single line with trailing newline\n', rev_id='a3'
213
, timestamp=1132587176.835228920, timezone=-6*3600
214
, committer = 'Joe Foo <joe@foo.com>')
218
class TestShortLogFormatter(TestCaseWithTransport):
287
220
def test_trailing_newlines(self):
288
221
wt = self.make_branch_and_tree('.')
289
b = self.make_commits_with_trailing_newlines(wt)
290
self.assertFormatterResult("""\
291
3 Joe Foo\t2005-11-22
222
b = make_commits_with_trailing_newlines(wt)
224
lf = ShortLogFormatter(to_file=sio)
226
self.assertEquals(sio.getvalue(), """\
227
3 Joe Foo\t2005-11-21
292
228
single line with trailing newline
294
2 Joe Foo\t2005-11-22
230
2 Joe Foo\t2005-11-21
299
1 Joe Foo\t2005-11-22
235
1 Joe Foo\t2005-11-21
300
236
simple log message
303
b, log.ShortLogFormatter)
305
def test_short_log_with_merges(self):
306
wt = self._prepare_tree_with_merges()
307
self.assertFormatterResult("""\
308
2 Joe Foo\t2005-11-22 [merge]
311
1 Joe Foo\t2005-11-22
315
wt.branch, log.ShortLogFormatter)
317
def test_short_log_with_merges_and_advice(self):
318
wt = self._prepare_tree_with_merges()
319
self.assertFormatterResult("""\
320
2 Joe Foo\t2005-11-22 [merge]
323
1 Joe Foo\t2005-11-22
326
Use --include-merges or -n0 to see merged revisions.
328
wt.branch, log.ShortLogFormatter,
329
formatter_kwargs=dict(show_advice=True))
331
def test_short_log_with_merges_and_range(self):
332
wt = self._prepare_tree_with_merges()
333
self.wt_commit(wt, 'rev-3a', rev_id='rev-3a')
334
wt.branch.set_last_revision_info(2, 'rev-2b')
335
wt.set_parent_ids(['rev-2b', 'rev-3a'])
336
self.wt_commit(wt, 'rev-3b', rev_id='rev-3b')
337
self.assertFormatterResult("""\
338
3 Joe Foo\t2005-11-22 [merge]
341
2 Joe Foo\t2005-11-22 [merge]
345
wt.branch, log.ShortLogFormatter,
346
show_log_kwargs=dict(start_revision=2, end_revision=3))
348
def test_short_log_with_tags(self):
349
wt = self._prepare_tree_with_merges(with_tags=True)
350
self.assertFormatterResult("""\
351
3 Joe Foo\t2005-11-22 {v1.0, v1.0rc1}
354
2 Joe Foo\t2005-11-22 {v0.2} [merge]
357
1 Joe Foo\t2005-11-22
361
wt.branch, log.ShortLogFormatter)
363
def test_short_log_single_merge_revision(self):
364
wt = self._prepare_tree_with_merges()
365
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
366
rev = revspec.in_history(wt.branch)
367
self.assertFormatterResult("""\
368
1.1.1 Joe Foo\t2005-11-22
372
wt.branch, log.ShortLogFormatter,
373
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
375
def test_show_ids(self):
376
wt = self.make_branch_and_tree('parent')
377
self.build_tree(['parent/f1', 'parent/f2'])
379
self.wt_commit(wt, 'first post', rev_id='a')
380
child_wt = wt.bzrdir.sprout('child').open_workingtree()
381
self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
382
wt.merge_from_branch(child_wt.branch)
383
self.wt_commit(wt, 'merge branch 1', rev_id='c')
384
self.assertFormatterResult("""\
385
2 Joe Foo\t2005-11-22 [merge]
389
1.1.1 Joe Foo\t2005-11-22
393
1 Joe Foo\t2005-11-22
398
wt.branch, log.ShortLogFormatter,
399
formatter_kwargs=dict(levels=0,show_ids=True))
402
class TestShortLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
404
def test_short_merge_revs_log_with_merges(self):
405
wt = self._prepare_tree_with_merges()
406
# Note that the 1.1.1 indenting is in fact correct given that
407
# the revision numbers are right justified within 5 characters
408
# for mainline revnos and 9 characters for dotted revnos.
409
self.assertFormatterResult("""\
410
2 Joe Foo\t2005-11-22 [merge]
413
1.1.1 Joe Foo\t2005-11-22
416
1 Joe Foo\t2005-11-22
420
wt.branch, log.ShortLogFormatter,
421
formatter_kwargs=dict(levels=0))
423
def test_short_merge_revs_log_single_merge_revision(self):
424
wt = self._prepare_tree_with_merges()
425
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
426
rev = revspec.in_history(wt.branch)
427
self.assertFormatterResult("""\
428
1.1.1 Joe Foo\t2005-11-22
432
wt.branch, log.ShortLogFormatter,
433
formatter_kwargs=dict(levels=0),
434
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
437
class TestLongLogFormatter(TestCaseForLogFormatter):
241
class TestLongLogFormatter(TestCaseWithTransport):
243
def normalize_log(self,log):
244
"""Replaces the variable lines of logs with fixed lines"""
245
committer = 'committer: Lorem Ipsum <test@example.com>'
246
lines = log.splitlines(True)
247
for idx,line in enumerate(lines):
248
stripped_line = line.lstrip()
249
indent = ' ' * (len(line) - len(stripped_line))
250
if stripped_line.startswith('committer:'):
251
lines[idx] = indent + committer + '\n'
252
if stripped_line.startswith('timestamp:'):
253
lines[idx] = indent + 'timestamp: Just now\n'
254
return ''.join(lines)
439
256
def test_verbose_log(self):
440
257
"""Verbose log includes changed files
444
wt = self.make_standard_commit('test_verbose_log', authors=[])
445
self.assertFormatterResult('''\
261
wt = self.make_branch_and_tree('.')
263
self.build_tree(['a'])
265
# XXX: why does a longer nick show up?
266
b.nick = 'test_verbose_log'
267
wt.commit(message='add a',
268
timestamp=1132711707,
270
committer='Lorem Ipsum <test@example.com>')
271
logfile = file('out.tmp', 'w+')
272
formatter = LongLogFormatter(to_file=logfile)
273
show_log(b, formatter, verbose=True)
276
log_contents = logfile.read()
277
self.assertEqualDiff(log_contents, '''\
446
278
------------------------------------------------------------
448
280
committer: Lorem Ipsum <test@example.com>
449
281
branch nick: test_verbose_log
450
timestamp: Tue 2005-11-22 00:00:00 +0000
282
timestamp: Wed 2005-11-23 12:08:27 +1000
456
wt.branch, log.LongLogFormatter,
457
show_log_kwargs=dict(verbose=True))
459
289
def test_merges_are_indented_by_level(self):
460
290
wt = self.make_branch_and_tree('parent')
461
self.wt_commit(wt, 'first post')
462
child_wt = wt.bzrdir.sprout('child').open_workingtree()
463
self.wt_commit(child_wt, 'branch 1')
464
smallerchild_wt = wt.bzrdir.sprout('smallerchild').open_workingtree()
465
self.wt_commit(smallerchild_wt, 'branch 2')
466
child_wt.merge_from_branch(smallerchild_wt.branch)
467
self.wt_commit(child_wt, 'merge branch 2')
468
wt.merge_from_branch(child_wt.branch)
469
self.wt_commit(wt, 'merge branch 1')
470
self.assertFormatterResult("""\
291
wt.commit('first post')
292
self.run_bzr('branch parent child')
293
self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
294
self.run_bzr('branch child smallerchild')
295
self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
298
self.run_bzr('merge ../smallerchild')
299
self.run_bzr(['commit', '-m', 'merge branch 2'])
300
os.chdir('../parent')
301
self.run_bzr('merge ../child')
302
wt.commit('merge branch 1')
305
lf = LongLogFormatter(to_file=sio)
306
show_log(b, lf, verbose=True)
307
log = self.normalize_log(sio.getvalue())
308
self.assertEqualDiff("""\
471
309
------------------------------------------------------------
473
committer: Joe Foo <joe@foo.com>
311
committer: Lorem Ipsum <test@example.com>
474
312
branch nick: parent
475
timestamp: Tue 2005-11-22 00:00:04 +0000
478
316
------------------------------------------------------------
480
committer: Joe Foo <joe@foo.com>
318
committer: Lorem Ipsum <test@example.com>
481
319
branch nick: child
482
timestamp: Tue 2005-11-22 00:00:03 +0000
485
323
------------------------------------------------------------
487
committer: Joe Foo <joe@foo.com>
325
committer: Lorem Ipsum <test@example.com>
488
326
branch nick: smallerchild
489
timestamp: Tue 2005-11-22 00:00:02 +0000
492
330
------------------------------------------------------------
494
committer: Joe Foo <joe@foo.com>
332
committer: Lorem Ipsum <test@example.com>
495
333
branch nick: child
496
timestamp: Tue 2005-11-22 00:00:01 +0000
499
337
------------------------------------------------------------
501
committer: Joe Foo <joe@foo.com>
339
committer: Lorem Ipsum <test@example.com>
502
340
branch nick: parent
503
timestamp: Tue 2005-11-22 00:00:00 +0000
507
wt.branch, log.LongLogFormatter,
508
formatter_kwargs=dict(levels=0),
509
show_log_kwargs=dict(verbose=True))
511
346
def test_verbose_merge_revisions_contain_deltas(self):
512
347
wt = self.make_branch_and_tree('parent')
513
348
self.build_tree(['parent/f1', 'parent/f2'])
514
349
wt.add(['f1','f2'])
515
self.wt_commit(wt, 'first post')
516
child_wt = wt.bzrdir.sprout('child').open_workingtree()
350
wt.commit('first post')
351
self.run_bzr('branch parent child')
517
352
os.unlink('child/f1')
518
self.build_tree_contents([('child/f2', 'hello\n')])
519
self.wt_commit(child_wt, 'removed f1 and modified f2')
520
wt.merge_from_branch(child_wt.branch)
521
self.wt_commit(wt, 'merge branch 1')
522
self.assertFormatterResult("""\
353
print >> file('child/f2', 'wb'), 'hello'
354
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
357
self.run_bzr('merge ../child')
358
wt.commit('merge branch 1')
361
lf = LongLogFormatter(to_file=sio)
362
show_log(b, lf, verbose=True)
363
log = self.normalize_log(sio.getvalue())
364
self.assertEqualDiff("""\
523
365
------------------------------------------------------------
525
committer: Joe Foo <joe@foo.com>
367
committer: Lorem Ipsum <test@example.com>
526
368
branch nick: parent
527
timestamp: Tue 2005-11-22 00:00:02 +0000
545
387
------------------------------------------------------------
547
committer: Joe Foo <joe@foo.com>
389
committer: Lorem Ipsum <test@example.com>
548
390
branch nick: parent
549
timestamp: Tue 2005-11-22 00:00:00 +0000
556
wt.branch, log.LongLogFormatter,
557
formatter_kwargs=dict(levels=0),
558
show_log_kwargs=dict(verbose=True))
560
399
def test_trailing_newlines(self):
561
400
wt = self.make_branch_and_tree('.')
562
b = self.make_commits_with_trailing_newlines(wt)
563
self.assertFormatterResult("""\
564
------------------------------------------------------------
566
committer: Joe Foo <joe@foo.com>
568
timestamp: Tue 2005-11-22 00:00:02 +0000
570
single line with trailing newline
571
------------------------------------------------------------
573
committer: Joe Foo <joe@foo.com>
575
timestamp: Tue 2005-11-22 00:00:01 +0000
580
------------------------------------------------------------
582
committer: Joe Foo <joe@foo.com>
584
timestamp: Tue 2005-11-22 00:00:00 +0000
588
b, log.LongLogFormatter)
590
def test_author_in_log(self):
591
"""Log includes the author name if it's set in
592
the revision properties
594
wt = self.make_standard_commit('test_author_log',
595
authors=['John Doe <jdoe@example.com>',
596
'Jane Rey <jrey@example.com>'])
597
self.assertFormatterResult("""\
598
------------------------------------------------------------
600
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
601
committer: Lorem Ipsum <test@example.com>
602
branch nick: test_author_log
603
timestamp: Tue 2005-11-22 00:00:00 +0000
607
wt.branch, log.LongLogFormatter)
609
def test_properties_in_log(self):
610
"""Log includes the custom properties returned by the registered
613
wt = self.make_standard_commit('test_properties_in_log')
614
def trivial_custom_prop_handler(revision):
615
return {'test_prop':'test_value'}
617
# Cleaned up in setUp()
618
log.properties_handler_registry.register(
619
'trivial_custom_prop_handler',
620
trivial_custom_prop_handler)
621
self.assertFormatterResult("""\
622
------------------------------------------------------------
624
test_prop: test_value
625
author: John Doe <jdoe@example.com>
626
committer: Lorem Ipsum <test@example.com>
627
branch nick: test_properties_in_log
628
timestamp: Tue 2005-11-22 00:00:00 +0000
632
wt.branch, log.LongLogFormatter)
634
def test_properties_in_short_log(self):
635
"""Log includes the custom properties returned by the registered
638
wt = self.make_standard_commit('test_properties_in_short_log')
639
def trivial_custom_prop_handler(revision):
640
return {'test_prop':'test_value'}
642
log.properties_handler_registry.register(
643
'trivial_custom_prop_handler',
644
trivial_custom_prop_handler)
645
self.assertFormatterResult("""\
646
1 John Doe\t2005-11-22
647
test_prop: test_value
651
wt.branch, log.ShortLogFormatter)
653
def test_error_in_properties_handler(self):
654
"""Log includes the custom properties returned by the registered
657
wt = self.make_standard_commit('error_in_properties_handler',
658
revprops={'first_prop':'first_value'})
659
sio = self.make_utf8_encoded_stringio()
660
formatter = log.LongLogFormatter(to_file=sio)
661
def trivial_custom_prop_handler(revision):
662
raise StandardError("a test error")
664
log.properties_handler_registry.register(
665
'trivial_custom_prop_handler',
666
trivial_custom_prop_handler)
667
self.assertRaises(StandardError, log.show_log, wt.branch, formatter,)
669
def test_properties_handler_bad_argument(self):
670
wt = self.make_standard_commit('bad_argument',
671
revprops={'a_prop':'test_value'})
672
sio = self.make_utf8_encoded_stringio()
673
formatter = log.LongLogFormatter(to_file=sio)
674
def bad_argument_prop_handler(revision):
675
return {'custom_prop_name':revision.properties['a_prop']}
677
log.properties_handler_registry.register(
678
'bad_argument_prop_handler',
679
bad_argument_prop_handler)
681
self.assertRaises(AttributeError, formatter.show_properties,
684
revision = wt.branch.repository.get_revision(wt.branch.last_revision())
685
formatter.show_properties(revision, '')
686
self.assertEqualDiff('''custom_prop_name: test_value\n''',
689
def test_show_ids(self):
690
wt = self.make_branch_and_tree('parent')
691
self.build_tree(['parent/f1', 'parent/f2'])
693
self.wt_commit(wt, 'first post', rev_id='a')
694
child_wt = wt.bzrdir.sprout('child').open_workingtree()
695
self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
696
wt.merge_from_branch(child_wt.branch)
697
self.wt_commit(wt, 'merge branch 1', rev_id='c')
698
self.assertFormatterResult("""\
699
------------------------------------------------------------
704
committer: Joe Foo <joe@foo.com>
706
timestamp: Tue 2005-11-22 00:00:02 +0000
709
------------------------------------------------------------
713
committer: Joe Foo <joe@foo.com>
715
timestamp: Tue 2005-11-22 00:00:01 +0000
718
------------------------------------------------------------
721
committer: Joe Foo <joe@foo.com>
723
timestamp: Tue 2005-11-22 00:00:00 +0000
727
wt.branch, log.LongLogFormatter,
728
formatter_kwargs=dict(levels=0,show_ids=True))
731
class TestLongLogFormatterWithoutMergeRevisions(TestCaseForLogFormatter):
733
def test_long_verbose_log(self):
734
"""Verbose log includes changed files
738
wt = self.make_standard_commit('test_long_verbose_log', authors=[])
739
self.assertFormatterResult("""\
740
------------------------------------------------------------
742
committer: Lorem Ipsum <test@example.com>
743
branch nick: test_long_verbose_log
744
timestamp: Tue 2005-11-22 00:00:00 +0000
750
wt.branch, log.LongLogFormatter,
751
formatter_kwargs=dict(levels=1),
752
show_log_kwargs=dict(verbose=True))
754
def test_long_verbose_contain_deltas(self):
755
wt = self.make_branch_and_tree('parent')
756
self.build_tree(['parent/f1', 'parent/f2'])
758
self.wt_commit(wt, 'first post')
759
child_wt = wt.bzrdir.sprout('child').open_workingtree()
760
os.unlink('child/f1')
761
self.build_tree_contents([('child/f2', 'hello\n')])
762
self.wt_commit(child_wt, 'removed f1 and modified f2')
763
wt.merge_from_branch(child_wt.branch)
764
self.wt_commit(wt, 'merge branch 1')
765
self.assertFormatterResult("""\
766
------------------------------------------------------------
768
committer: Joe Foo <joe@foo.com>
770
timestamp: Tue 2005-11-22 00:00:02 +0000
777
------------------------------------------------------------
779
committer: Joe Foo <joe@foo.com>
781
timestamp: Tue 2005-11-22 00:00:00 +0000
788
wt.branch, log.LongLogFormatter,
789
formatter_kwargs=dict(levels=1),
790
show_log_kwargs=dict(verbose=True))
792
def test_long_trailing_newlines(self):
793
wt = self.make_branch_and_tree('.')
794
b = self.make_commits_with_trailing_newlines(wt)
795
self.assertFormatterResult("""\
796
------------------------------------------------------------
798
committer: Joe Foo <joe@foo.com>
800
timestamp: Tue 2005-11-22 00:00:02 +0000
802
single line with trailing newline
803
------------------------------------------------------------
805
committer: Joe Foo <joe@foo.com>
807
timestamp: Tue 2005-11-22 00:00:01 +0000
812
------------------------------------------------------------
814
committer: Joe Foo <joe@foo.com>
816
timestamp: Tue 2005-11-22 00:00:00 +0000
820
b, log.LongLogFormatter,
821
formatter_kwargs=dict(levels=1))
823
def test_long_author_in_log(self):
824
"""Log includes the author name if it's set in
825
the revision properties
827
wt = self.make_standard_commit('test_author_log')
828
self.assertFormatterResult("""\
829
------------------------------------------------------------
831
author: John Doe <jdoe@example.com>
832
committer: Lorem Ipsum <test@example.com>
833
branch nick: test_author_log
834
timestamp: Tue 2005-11-22 00:00:00 +0000
838
wt.branch, log.LongLogFormatter,
839
formatter_kwargs=dict(levels=1))
841
def test_long_properties_in_log(self):
842
"""Log includes the custom properties returned by the registered
845
wt = self.make_standard_commit('test_properties_in_log')
846
def trivial_custom_prop_handler(revision):
847
return {'test_prop':'test_value'}
849
log.properties_handler_registry.register(
850
'trivial_custom_prop_handler',
851
trivial_custom_prop_handler)
852
self.assertFormatterResult("""\
853
------------------------------------------------------------
855
test_prop: test_value
856
author: John Doe <jdoe@example.com>
857
committer: Lorem Ipsum <test@example.com>
858
branch nick: test_properties_in_log
859
timestamp: Tue 2005-11-22 00:00:00 +0000
863
wt.branch, log.LongLogFormatter,
864
formatter_kwargs=dict(levels=1))
867
class TestLineLogFormatter(TestCaseForLogFormatter):
401
b = make_commits_with_trailing_newlines(wt)
403
lf = LongLogFormatter(to_file=sio)
405
self.assertEqualDiff(sio.getvalue(), """\
406
------------------------------------------------------------
408
committer: Joe Foo <joe@foo.com>
410
timestamp: Mon 2005-11-21 09:32:56 -0600
412
single line with trailing newline
413
------------------------------------------------------------
415
committer: Joe Foo <joe@foo.com>
417
timestamp: Mon 2005-11-21 09:27:22 -0600
422
------------------------------------------------------------
424
committer: Joe Foo <joe@foo.com>
426
timestamp: Mon 2005-11-21 09:24:15 -0600
432
class TestLineLogFormatter(TestCaseWithTransport):
869
434
def test_line_log(self):
870
435
"""Line log should show revno
874
wt = self.make_standard_commit('test-line-log',
875
committer='Line-Log-Formatter Tester <test@line.log>',
877
self.assertFormatterResult("""\
878
1: Line-Log-Formatte... 2005-11-22 add a
880
wt.branch, log.LineLogFormatter)
439
wt = self.make_branch_and_tree('.')
441
self.build_tree(['a'])
443
b.nick = 'test-line-log'
444
wt.commit(message='add a',
445
timestamp=1132711707,
447
committer='Line-Log-Formatter Tester <test@line.log>')
448
logfile = file('out.tmp', 'w+')
449
formatter = LineLogFormatter(to_file=logfile)
450
show_log(b, formatter)
453
log_contents = logfile.read()
454
self.assertEqualDiff(log_contents, '1: Line-Log-Formatte... 2005-11-23 add a\n')
456
def test_short_log_with_merges(self):
457
wt = self.make_branch_and_memory_tree('.')
461
wt.commit('rev-1', rev_id='rev-1',
462
timestamp=1132586655, timezone=36000,
463
committer='Joe Foo <joe@foo.com>')
464
wt.commit('rev-merged', rev_id='rev-2a',
465
timestamp=1132586700, timezone=36000,
466
committer='Joe Foo <joe@foo.com>')
467
wt.set_parent_ids(['rev-1', 'rev-2a'])
468
wt.branch.set_last_revision_info(1, 'rev-1')
469
wt.commit('rev-2', rev_id='rev-2b',
470
timestamp=1132586800, timezone=36000,
471
committer='Joe Foo <joe@foo.com>')
473
formatter = ShortLogFormatter(to_file=logfile)
474
show_log(wt.branch, formatter)
476
self.assertEqualDiff("""\
477
2 Joe Foo\t2005-11-22 [merge]
480
1 Joe Foo\t2005-11-22
483
""", logfile.getvalue())
882
487
def test_trailing_newlines(self):
883
488
wt = self.make_branch_and_tree('.')
884
b = self.make_commits_with_trailing_newlines(wt)
885
self.assertFormatterResult("""\
886
3: Joe Foo 2005-11-22 single line with trailing newline
887
2: Joe Foo 2005-11-22 multiline
888
1: Joe Foo 2005-11-22 simple log message
890
b, log.LineLogFormatter)
892
def test_line_log_single_merge_revision(self):
893
wt = self._prepare_tree_with_merges()
894
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
895
rev = revspec.in_history(wt.branch)
896
self.assertFormatterResult("""\
897
1.1.1: Joe Foo 2005-11-22 rev-merged
899
wt.branch, log.LineLogFormatter,
900
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
902
def test_line_log_with_tags(self):
903
wt = self._prepare_tree_with_merges(with_tags=True)
904
self.assertFormatterResult("""\
905
3: Joe Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
906
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
907
1: Joe Foo 2005-11-22 rev-1
909
wt.branch, log.LineLogFormatter)
912
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
914
def test_line_merge_revs_log(self):
915
"""Line log should show revno
919
wt = self.make_standard_commit('test-line-log',
920
committer='Line-Log-Formatter Tester <test@line.log>',
922
self.assertFormatterResult("""\
923
1: Line-Log-Formatte... 2005-11-22 add a
925
wt.branch, log.LineLogFormatter)
927
def test_line_merge_revs_log_single_merge_revision(self):
928
wt = self._prepare_tree_with_merges()
929
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
930
rev = revspec.in_history(wt.branch)
931
self.assertFormatterResult("""\
932
1.1.1: Joe Foo 2005-11-22 rev-merged
934
wt.branch, log.LineLogFormatter,
935
formatter_kwargs=dict(levels=0),
936
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
938
def test_line_merge_revs_log_with_merges(self):
939
wt = self._prepare_tree_with_merges()
940
self.assertFormatterResult("""\
941
2: Joe Foo 2005-11-22 [merge] rev-2
942
1.1.1: Joe Foo 2005-11-22 rev-merged
943
1: Joe Foo 2005-11-22 rev-1
945
wt.branch, log.LineLogFormatter,
946
formatter_kwargs=dict(levels=0))
949
class TestGnuChangelogFormatter(TestCaseForLogFormatter):
951
def test_gnu_changelog(self):
952
wt = self.make_standard_commit('nicky', authors=[])
953
self.assertFormatterResult('''\
954
2005-11-22 Lorem Ipsum <test@example.com>
959
wt.branch, log.GnuChangelogLogFormatter)
961
def test_with_authors(self):
962
wt = self.make_standard_commit('nicky',
963
authors=['Fooa Fooz <foo@example.com>',
964
'Bari Baro <bar@example.com>'])
965
self.assertFormatterResult('''\
966
2005-11-22 Fooa Fooz <foo@example.com>
971
wt.branch, log.GnuChangelogLogFormatter)
973
def test_verbose(self):
974
wt = self.make_standard_commit('nicky')
975
self.assertFormatterResult('''\
976
2005-11-22 John Doe <jdoe@example.com>
983
wt.branch, log.GnuChangelogLogFormatter,
984
show_log_kwargs=dict(verbose=True))
986
class TestGetViewRevisions(tests.TestCaseWithTransport, TestLogMixin):
988
def _get_view_revisions(self, *args, **kwargs):
989
return self.applyDeprecated(symbol_versioning.deprecated_in((2, 2, 0)),
990
log.get_view_revisions, *args, **kwargs)
489
b = make_commits_with_trailing_newlines(wt)
491
lf = LineLogFormatter(to_file=sio)
493
self.assertEqualDiff(sio.getvalue(), """\
494
3: Joe Foo 2005-11-21 single line with trailing newline
495
2: Joe Foo 2005-11-21 multiline
496
1: Joe Foo 2005-11-21 simple log message
500
class TestGetViewRevisions(TestCaseWithTransport):
992
502
def make_tree_with_commits(self):
993
503
"""Create a tree with well-known revision ids"""
994
504
wt = self.make_branch_and_tree('tree1')
995
self.wt_commit(wt, 'commit one', rev_id='1')
996
self.wt_commit(wt, 'commit two', rev_id='2')
997
self.wt_commit(wt, 'commit three', rev_id='3')
505
wt.commit('commit one', rev_id='1')
506
wt.commit('commit two', rev_id='2')
507
wt.commit('commit three', rev_id='3')
998
508
mainline_revs = [None, '1', '2', '3']
999
509
rev_nos = {'1': 1, '2': 2, '3': 3}
1000
510
return mainline_revs, rev_nos, wt
1003
513
"""Create a tree with well-known revision ids and a merge"""
1004
514
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1005
515
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1006
self.wt_commit(tree2, 'four-a', rev_id='4a')
516
tree2.commit('four-a', rev_id='4a')
1007
517
wt.merge_from_branch(tree2.branch)
1008
self.wt_commit(wt, 'four-b', rev_id='4b')
518
wt.commit('four-b', rev_id='4b')
1009
519
mainline_revs.append('4b')
1010
520
rev_nos['4b'] = 4
1012
522
return mainline_revs, rev_nos, wt
1014
def make_branch_with_many_merges(self):
524
def make_tree_with_many_merges(self):
1015
525
"""Create a tree with well-known revision ids"""
1016
builder = self.make_branch_builder('tree1')
1017
builder.start_series()
1018
builder.build_snapshot('1', None, [
1019
('add', ('', 'TREE_ROOT', 'directory', '')),
1020
('add', ('f', 'f-id', 'file', '1\n'))])
1021
builder.build_snapshot('2', ['1'], [])
1022
builder.build_snapshot('3a', ['2'], [
1023
('modify', ('f-id', '1\n2\n3a\n'))])
1024
builder.build_snapshot('3b', ['2', '3a'], [
1025
('modify', ('f-id', '1\n2\n3a\n'))])
1026
builder.build_snapshot('3c', ['2', '3b'], [
1027
('modify', ('f-id', '1\n2\n3a\n'))])
1028
builder.build_snapshot('4a', ['3b'], [])
1029
builder.build_snapshot('4b', ['3c', '4a'], [])
1030
builder.finish_series()
526
wt = self.make_branch_and_tree('tree1')
527
wt.commit('commit one', rev_id='1')
528
wt.commit('commit two', rev_id='2')
529
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
530
tree3.commit('commit three a', rev_id='3a')
531
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
532
tree2.merge_from_branch(tree3.branch)
533
tree2.commit('commit three b', rev_id='3b')
534
wt.merge_from_branch(tree2.branch)
535
wt.commit('commit three c', rev_id='3c')
536
tree2.commit('four-a', rev_id='4a')
537
wt.merge_from_branch(tree2.branch)
538
wt.commit('four-b', rev_id='4b')
1044
539
mainline_revs = [None, '1', '2', '3c', '4b']
1045
540
rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
1046
541
full_rev_nos_for_reference = {
1049
'3a': '2.1.1', #first commit tree 3
1050
'3b': '2.2.1', # first commit tree 2
544
'3a': '2.2.1', #first commit tree 3
545
'3b': '2.1.1', # first commit tree 2
1051
546
'3c': '3', #merges 3b to main
1052
'4a': '2.2.2', # second commit tree 2
547
'4a': '2.1.2', # second commit tree 2
1053
548
'4b': '4', # merges 4a to main
1055
return mainline_revs, rev_nos, builder.get_branch()
550
return mainline_revs, rev_nos, wt
1057
552
def test_get_view_revisions_forward(self):
1058
553
"""Test the get_view_revisions method"""
1059
554
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1061
self.addCleanup(wt.unlock)
1062
revisions = list(self._get_view_revisions(
1063
mainline_revs, rev_nos, wt.branch, 'forward'))
555
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
1064
557
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
1066
revisions2 = list(self._get_view_revisions(
1067
mainline_revs, rev_nos, wt.branch, 'forward',
1068
include_merges=False))
559
revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
560
'forward', include_merges=False))
1069
561
self.assertEqual(revisions, revisions2)
1071
563
def test_get_view_revisions_reverse(self):
1072
564
"""Test the get_view_revisions with reverse"""
1073
565
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1075
self.addCleanup(wt.unlock)
1076
revisions = list(self._get_view_revisions(
1077
mainline_revs, rev_nos, wt.branch, 'reverse'))
566
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
1078
568
self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
1080
revisions2 = list(self._get_view_revisions(
1081
mainline_revs, rev_nos, wt.branch, 'reverse',
1082
include_merges=False))
570
revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
571
'reverse', include_merges=False))
1083
572
self.assertEqual(revisions, revisions2)
1085
574
def test_get_view_revisions_merge(self):
1086
575
"""Test get_view_revisions when there are merges"""
1087
576
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1089
self.addCleanup(wt.unlock)
1090
revisions = list(self._get_view_revisions(
1091
mainline_revs, rev_nos, wt.branch, 'forward'))
1092
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1093
('4b', '4', 0), ('4a', '3.1.1', 1)],
1095
revisions = list(self._get_view_revisions(
1096
mainline_revs, rev_nos, wt.branch, 'forward',
1097
include_merges=False))
1098
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
577
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
579
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
580
('4b', '4', 0), ('4a', '3.1.1', 1)],
582
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
583
'forward', include_merges=False))
584
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1102
588
def test_get_view_revisions_merge_reverse(self):
1103
589
"""Test get_view_revisions in reverse when there are merges"""
1104
590
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1106
self.addCleanup(wt.unlock)
1107
revisions = list(self._get_view_revisions(
1108
mainline_revs, rev_nos, wt.branch, 'reverse'))
591
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
1109
593
self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
1110
('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
1112
revisions = list(self._get_view_revisions(
1113
mainline_revs, rev_nos, wt.branch, 'reverse',
1114
include_merges=False))
594
('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
596
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
597
'reverse', include_merges=False))
1115
598
self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
1119
602
def test_get_view_revisions_merge2(self):
1120
603
"""Test get_view_revisions when there are merges"""
1121
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1123
self.addCleanup(b.unlock)
1124
revisions = list(self._get_view_revisions(
1125
mainline_revs, rev_nos, b, 'forward'))
604
mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
605
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
1126
607
expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1127
('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
608
('3a', '2.2.1', 1), ('3b', '2.1.1', 1), ('4b', '4', 0),
1129
610
self.assertEqual(expected, revisions)
1130
revisions = list(self._get_view_revisions(
1131
mainline_revs, rev_nos, b, 'forward',
1132
include_merges=False))
611
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
612
'forward', include_merges=False))
1133
613
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1137
def test_file_id_for_range(self):
1138
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1140
self.addCleanup(b.unlock)
1142
def rev_from_rev_id(revid, branch):
1143
revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1144
return revspec.in_history(branch)
1146
def view_revs(start_rev, end_rev, file_id, direction):
1147
revs = self.applyDeprecated(
1148
symbol_versioning.deprecated_in((2, 2, 0)),
1149
log.calculate_view_revisions,
1151
start_rev, # start_revision
1152
end_rev, # end_revision
1153
direction, # direction
1154
file_id, # specific_fileid
1155
True, # generate_merge_revisions
1159
rev_3a = rev_from_rev_id('3a', b)
1160
rev_4b = rev_from_rev_id('4b', b)
1161
self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
1162
('3a', '2.1.1', 2)],
1163
view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
1164
# Note: 3c still appears before 3a here because of depth-based sorting
1165
self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
1166
('3a', '2.1.1', 2)],
1167
view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
1170
class TestGetRevisionsTouchingFileID(tests.TestCaseWithTransport):
1172
def get_view_revisions(self, *args):
1173
return self.applyDeprecated(symbol_versioning.deprecated_in((2, 2, 0)),
1174
log.get_view_revisions, *args)
618
class TestGetRevisionsTouchingFileID(TestCaseWithTransport):
1176
620
def create_tree_with_single_merge(self):
1177
621
"""Create a branch with a moderate layout.
1301
746
def test_file_id_f3(self):
1302
747
tree = self.create_tree_with_single_merge()
1303
748
# f3 should be marked as modified by revisions A, B, C, and D
1304
self.assertAllRevisionsForFileID(tree, 'f3-id', ['D', 'C', 'B', 'A'])
1306
def test_file_id_with_ghosts(self):
1307
# This is testing bug #209948, where having a ghost would cause
1308
# _filter_revisions_touching_file_id() to fail.
1309
tree = self.create_tree_with_single_merge()
1310
# We need to add a revision, so switch back to a write-locked tree
1311
# (still a single addCleanup(tree.unlock) pending).
1314
first_parent = tree.last_revision()
1315
tree.set_parent_ids([first_parent, 'ghost-revision-id'])
1316
self.build_tree_contents([('tree/f1', 'A\nB\nXX\n')])
1317
tree.commit('commit with a ghost', rev_id='XX')
1318
self.assertAllRevisionsForFileID(tree, 'f1-id', ['XX', 'B', 'A'])
1319
749
self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1321
def test_unknown_file_id(self):
1322
tree = self.create_tree_with_single_merge()
1323
self.assertAllRevisionsForFileID(tree, 'unknown', [])
1325
def test_empty_branch_unknown_file_id(self):
1326
tree = self.make_branch_and_tree('tree')
1327
self.assertAllRevisionsForFileID(tree, 'unknown', [])
1330
class TestShowChangedRevisions(tests.TestCaseWithTransport):
1332
def test_show_changed_revisions_verbose(self):
1333
tree = self.make_branch_and_tree('tree_a')
1334
self.build_tree(['tree_a/foo'])
1336
tree.commit('bar', rev_id='bar-id')
1337
s = self.make_utf8_encoded_stringio()
1338
log.show_changed_revisions(tree.branch, [], ['bar-id'], s)
1339
self.assertContainsRe(s.getvalue(), 'bar')
1340
self.assertNotContainsRe(s.getvalue(), 'foo')
1343
class TestLogFormatter(tests.TestCase):
1346
super(TestLogFormatter, self).setUp()
1347
self.rev = revision.Revision('a-id')
1348
self.lf = log.LogFormatter(None)
1350
def test_short_committer(self):
1351
def assertCommitter(expected, committer):
1352
self.rev.committer = committer
1353
self.assertEqual(expected, self.lf.short_committer(self.rev))
1355
assertCommitter('John Doe', 'John Doe <jdoe@example.com>')
1356
assertCommitter('John Smith', 'John Smith <jsmith@example.com>')
1357
assertCommitter('John Smith', 'John Smith')
1358
assertCommitter('jsmith@example.com', 'jsmith@example.com')
1359
assertCommitter('jsmith@example.com', '<jsmith@example.com>')
1360
assertCommitter('John Smith', 'John Smith jsmith@example.com')
1362
def test_short_author(self):
1363
def assertAuthor(expected, author):
1364
self.rev.properties['author'] = author
1365
self.assertEqual(expected, self.lf.short_author(self.rev))
1367
assertAuthor('John Smith', 'John Smith <jsmith@example.com>')
1368
assertAuthor('John Smith', 'John Smith')
1369
assertAuthor('jsmith@example.com', 'jsmith@example.com')
1370
assertAuthor('jsmith@example.com', '<jsmith@example.com>')
1371
assertAuthor('John Smith', 'John Smith jsmith@example.com')
1373
def test_short_author_from_committer(self):
1374
self.rev.committer = 'John Doe <jdoe@example.com>'
1375
self.assertEqual('John Doe', self.lf.short_author(self.rev))
1377
def test_short_author_from_authors(self):
1378
self.rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1379
'Jane Rey <jrey@example.com>')
1380
self.assertEqual('John Smith', self.lf.short_author(self.rev))
1383
class TestReverseByDepth(tests.TestCase):
1384
"""Test reverse_by_depth behavior.
1386
This is used to present revisions in forward (oldest first) order in a nice
1389
The tests use lighter revision description to ease reading.
1392
def assertReversed(self, forward, backward):
1393
# Transform the descriptions to suit the API: tests use (revno, depth),
1394
# while the API expects (revid, revno, depth)
1395
def complete_revisions(l):
1396
"""Transform the description to suit the API.
1398
Tests use (revno, depth) whil the API expects (revid, revno, depth).
1399
Since the revid is arbitrary, we just duplicate revno
1401
return [ (r, r, d) for r, d in l]
1402
forward = complete_revisions(forward)
1403
backward= complete_revisions(backward)
1404
self.assertEqual(forward, log.reverse_by_depth(backward))
1407
def test_mainline_revisions(self):
1408
self.assertReversed([( '1', 0), ('2', 0)],
1409
[('2', 0), ('1', 0)])
1411
def test_merged_revisions(self):
1412
self.assertReversed([('1', 0), ('2', 0), ('2.2', 1), ('2.1', 1),],
1413
[('2', 0), ('2.1', 1), ('2.2', 1), ('1', 0),])
1414
def test_shifted_merged_revisions(self):
1415
"""Test irregular layout.
1417
Requesting revisions touching a file can produce "holes" in the depths.
1419
self.assertReversed([('1', 0), ('2', 0), ('1.1', 2), ('1.2', 2),],
1420
[('2', 0), ('1.2', 2), ('1.1', 2), ('1', 0),])
1422
def test_merged_without_child_revisions(self):
1423
"""Test irregular layout.
1425
Revision ranges can produce "holes" in the depths.
1427
# When a revision of higher depth doesn't follow one of lower depth, we
1428
# assume a lower depth one is virtually there
1429
self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1430
[('4', 4), ('3', 3), ('2', 2), ('1', 2),])
1431
# So we get the same order after reversing below even if the original
1432
# revisions are not in the same order.
1433
self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1434
[('3', 3), ('4', 4), ('2', 2), ('1', 2),])
1437
class TestHistoryChange(tests.TestCaseWithTransport):
1439
def setup_a_tree(self):
1440
tree = self.make_branch_and_tree('tree')
1442
self.addCleanup(tree.unlock)
1443
tree.commit('1a', rev_id='1a')
1444
tree.commit('2a', rev_id='2a')
1445
tree.commit('3a', rev_id='3a')
1448
def setup_ab_tree(self):
1449
tree = self.setup_a_tree()
1450
tree.set_last_revision('1a')
1451
tree.branch.set_last_revision_info(1, '1a')
1452
tree.commit('2b', rev_id='2b')
1453
tree.commit('3b', rev_id='3b')
1456
def setup_ac_tree(self):
1457
tree = self.setup_a_tree()
1458
tree.set_last_revision(revision.NULL_REVISION)
1459
tree.branch.set_last_revision_info(0, revision.NULL_REVISION)
1460
tree.commit('1c', rev_id='1c')
1461
tree.commit('2c', rev_id='2c')
1462
tree.commit('3c', rev_id='3c')
1465
def test_all_new(self):
1466
tree = self.setup_ab_tree()
1467
old, new = log.get_history_change('1a', '3a', tree.branch.repository)
1468
self.assertEqual([], old)
1469
self.assertEqual(['2a', '3a'], new)
1471
def test_all_old(self):
1472
tree = self.setup_ab_tree()
1473
old, new = log.get_history_change('3a', '1a', tree.branch.repository)
1474
self.assertEqual([], new)
1475
self.assertEqual(['2a', '3a'], old)
1477
def test_null_old(self):
1478
tree = self.setup_ab_tree()
1479
old, new = log.get_history_change(revision.NULL_REVISION,
1480
'3a', tree.branch.repository)
1481
self.assertEqual([], old)
1482
self.assertEqual(['1a', '2a', '3a'], new)
1484
def test_null_new(self):
1485
tree = self.setup_ab_tree()
1486
old, new = log.get_history_change('3a', revision.NULL_REVISION,
1487
tree.branch.repository)
1488
self.assertEqual([], new)
1489
self.assertEqual(['1a', '2a', '3a'], old)
1491
def test_diverged(self):
1492
tree = self.setup_ab_tree()
1493
old, new = log.get_history_change('3a', '3b', tree.branch.repository)
1494
self.assertEqual(old, ['2a', '3a'])
1495
self.assertEqual(new, ['2b', '3b'])
1497
def test_unrelated(self):
1498
tree = self.setup_ac_tree()
1499
old, new = log.get_history_change('3a', '3c', tree.branch.repository)
1500
self.assertEqual(old, ['1a', '2a', '3a'])
1501
self.assertEqual(new, ['1c', '2c', '3c'])
1503
def test_show_branch_change(self):
1504
tree = self.setup_ab_tree()
1506
log.show_branch_change(tree.branch, s, 3, '3a')
1507
self.assertContainsRe(s.getvalue(),
1508
'[*]{60}\nRemoved Revisions:\n(.|\n)*2a(.|\n)*3a(.|\n)*'
1509
'[*]{60}\n\nAdded Revisions:\n(.|\n)*2b(.|\n)*3b')
1511
def test_show_branch_change_no_change(self):
1512
tree = self.setup_ab_tree()
1514
log.show_branch_change(tree.branch, s, 3, '3b')
1515
self.assertEqual(s.getvalue(),
1516
'Nothing seems to have changed\n')
1518
def test_show_branch_change_no_old(self):
1519
tree = self.setup_ab_tree()
1521
log.show_branch_change(tree.branch, s, 2, '2b')
1522
self.assertContainsRe(s.getvalue(), 'Added Revisions:')
1523
self.assertNotContainsRe(s.getvalue(), 'Removed Revisions:')
1525
def test_show_branch_change_no_new(self):
1526
tree = self.setup_ab_tree()
1527
tree.branch.set_last_revision_info(2, '2b')
1529
log.show_branch_change(tree.branch, s, 3, '3b')
1530
self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1531
self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
1534
class TestRevisionNotInBranch(TestCaseForLogFormatter):
1536
def setup_a_tree(self):
1537
tree = self.make_branch_and_tree('tree')
1539
self.addCleanup(tree.unlock)
1541
'committer': 'Joe Foo <joe@foo.com>',
1542
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1543
'timezone': 0, # UTC
1545
tree.commit('commit 1a', rev_id='1a', **kwargs)
1546
tree.commit('commit 2a', rev_id='2a', **kwargs)
1547
tree.commit('commit 3a', rev_id='3a', **kwargs)
1550
def setup_ab_tree(self):
1551
tree = self.setup_a_tree()
1552
tree.set_last_revision('1a')
1553
tree.branch.set_last_revision_info(1, '1a')
1555
'committer': 'Joe Foo <joe@foo.com>',
1556
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1557
'timezone': 0, # UTC
1559
tree.commit('commit 2b', rev_id='2b', **kwargs)
1560
tree.commit('commit 3b', rev_id='3b', **kwargs)
1563
def test_one_revision(self):
1564
tree = self.setup_ab_tree()
1566
rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1567
log.show_log(tree.branch, lf, verbose=True, start_revision=rev,
1569
self.assertEqual(1, len(lf.revisions))
1570
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1571
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1573
def test_many_revisions(self):
1574
tree = self.setup_ab_tree()
1576
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1577
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1578
log.show_log(tree.branch, lf, verbose=True, start_revision=start_rev,
1579
end_revision=end_rev)
1580
self.assertEqual(3, len(lf.revisions))
1581
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1582
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1583
self.assertEqual(None, lf.revisions[1].revno) # Out-of-branch
1584
self.assertEqual('2a', lf.revisions[1].rev.revision_id)
1585
self.assertEqual('1', lf.revisions[2].revno) # In-branch
1587
def test_long_format(self):
1588
tree = self.setup_ab_tree()
1589
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1590
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1591
self.assertFormatterResult("""\
1592
------------------------------------------------------------
1594
committer: Joe Foo <joe@foo.com>
1596
timestamp: Tue 2005-11-22 00:00:00 +0000
1599
------------------------------------------------------------
1601
committer: Joe Foo <joe@foo.com>
1603
timestamp: Tue 2005-11-22 00:00:00 +0000
1606
------------------------------------------------------------
1608
committer: Joe Foo <joe@foo.com>
1610
timestamp: Tue 2005-11-22 00:00:00 +0000
1614
tree.branch, log.LongLogFormatter, show_log_kwargs={
1615
'start_revision': start_rev, 'end_revision': end_rev
1618
def test_short_format(self):
1619
tree = self.setup_ab_tree()
1620
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1621
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1622
self.assertFormatterResult("""\
1631
1 Joe Foo\t2005-11-22
1635
tree.branch, log.ShortLogFormatter, show_log_kwargs={
1636
'start_revision': start_rev, 'end_revision': end_rev
1639
def test_line_format(self):
1640
tree = self.setup_ab_tree()
1641
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1642
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1643
self.assertFormatterResult("""\
1644
Joe Foo 2005-11-22 commit 3a
1645
Joe Foo 2005-11-22 commit 2a
1646
1: Joe Foo 2005-11-22 commit 1a
1648
tree.branch, log.LineLogFormatter, show_log_kwargs={
1649
'start_revision': start_rev, 'end_revision': end_rev
1653
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1656
TestCaseForLogFormatter.setUp(self)
1657
log.properties_handler_registry.register(
1658
'bugs_properties_handler',
1659
log._bugs_properties_handler)
1661
def make_commits_with_bugs(self):
1662
"""Helper method for LogFormatter tests"""
1663
tree = self.make_branch_and_tree(u'.')
1664
self.build_tree(['a', 'b'])
1666
self.wt_commit(tree, 'simple log message', rev_id='a1',
1667
revprops={'bugs': 'test://bug/id fixed'})
1669
self.wt_commit(tree, 'multiline\nlog\nmessage\n', rev_id='a2',
1670
authors=['Joe Bar <joe@bar.com>'],
1671
revprops={'bugs': 'test://bug/id fixed\n'
1672
'test://bug/2 fixed'})
1676
def test_long_bugs(self):
1677
tree = self.make_commits_with_bugs()
1678
self.assertFormatterResult("""\
1679
------------------------------------------------------------
1681
fixes bug(s): test://bug/id test://bug/2
1682
author: Joe Bar <joe@bar.com>
1683
committer: Joe Foo <joe@foo.com>
1685
timestamp: Tue 2005-11-22 00:00:01 +0000
1690
------------------------------------------------------------
1692
fixes bug(s): test://bug/id
1693
committer: Joe Foo <joe@foo.com>
1695
timestamp: Tue 2005-11-22 00:00:00 +0000
1699
tree.branch, log.LongLogFormatter)
1701
def test_short_bugs(self):
1702
tree = self.make_commits_with_bugs()
1703
self.assertFormatterResult("""\
1704
2 Joe Bar\t2005-11-22
1705
fixes bug(s): test://bug/id test://bug/2
1710
1 Joe Foo\t2005-11-22
1711
fixes bug(s): test://bug/id
1715
tree.branch, log.ShortLogFormatter)
1717
def test_wrong_bugs_property(self):
1718
tree = self.make_branch_and_tree(u'.')
1719
self.build_tree(['foo'])
1720
self.wt_commit(tree, 'simple log message', rev_id='a1',
1721
revprops={'bugs': 'test://bug/id invalid_value'})
1722
self.assertFormatterResult("""\
1723
1 Joe Foo\t2005-11-22
1727
tree.branch, log.ShortLogFormatter)
1729
def test_bugs_handler_present(self):
1730
self.properties_handler_registry.get('bugs_properties_handler')
1733
class TestLogForAuthors(TestCaseForLogFormatter):
1736
TestCaseForLogFormatter.setUp(self)
1737
self.wt = self.make_standard_commit('nicky',
1738
authors=['John Doe <jdoe@example.com>',
1739
'Jane Rey <jrey@example.com>'])
1741
def assertFormatterResult(self, formatter, who, result):
1742
formatter_kwargs = dict()
1744
author_list_handler = log.author_list_registry.get(who)
1745
formatter_kwargs['author_list_handler'] = author_list_handler
1746
TestCaseForLogFormatter.assertFormatterResult(self, result,
1747
self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
1749
def test_line_default(self):
1750
self.assertFormatterResult(log.LineLogFormatter, None, """\
1751
1: John Doe 2005-11-22 add a
1754
def test_line_committer(self):
1755
self.assertFormatterResult(log.LineLogFormatter, 'committer', """\
1756
1: Lorem Ipsum 2005-11-22 add a
1759
def test_line_first(self):
1760
self.assertFormatterResult(log.LineLogFormatter, 'first', """\
1761
1: John Doe 2005-11-22 add a
1764
def test_line_all(self):
1765
self.assertFormatterResult(log.LineLogFormatter, 'all', """\
1766
1: John Doe, Jane Rey 2005-11-22 add a
1770
def test_short_default(self):
1771
self.assertFormatterResult(log.ShortLogFormatter, None, """\
1772
1 John Doe\t2005-11-22
1777
def test_short_committer(self):
1778
self.assertFormatterResult(log.ShortLogFormatter, 'committer', """\
1779
1 Lorem Ipsum\t2005-11-22
1784
def test_short_first(self):
1785
self.assertFormatterResult(log.ShortLogFormatter, 'first', """\
1786
1 John Doe\t2005-11-22
1791
def test_short_all(self):
1792
self.assertFormatterResult(log.ShortLogFormatter, 'all', """\
1793
1 John Doe, Jane Rey\t2005-11-22
1798
def test_long_default(self):
1799
self.assertFormatterResult(log.LongLogFormatter, None, """\
1800
------------------------------------------------------------
1802
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1803
committer: Lorem Ipsum <test@example.com>
1805
timestamp: Tue 2005-11-22 00:00:00 +0000
1810
def test_long_committer(self):
1811
self.assertFormatterResult(log.LongLogFormatter, 'committer', """\
1812
------------------------------------------------------------
1814
committer: Lorem Ipsum <test@example.com>
1816
timestamp: Tue 2005-11-22 00:00:00 +0000
1821
def test_long_first(self):
1822
self.assertFormatterResult(log.LongLogFormatter, 'first', """\
1823
------------------------------------------------------------
1825
author: John Doe <jdoe@example.com>
1826
committer: Lorem Ipsum <test@example.com>
1828
timestamp: Tue 2005-11-22 00:00:00 +0000
1833
def test_long_all(self):
1834
self.assertFormatterResult(log.LongLogFormatter, 'all', """\
1835
------------------------------------------------------------
1837
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1838
committer: Lorem Ipsum <test@example.com>
1840
timestamp: Tue 2005-11-22 00:00:00 +0000
1845
def test_gnu_changelog_default(self):
1846
self.assertFormatterResult(log.GnuChangelogLogFormatter, None, """\
1847
2005-11-22 John Doe <jdoe@example.com>
1853
def test_gnu_changelog_committer(self):
1854
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'committer', """\
1855
2005-11-22 Lorem Ipsum <test@example.com>
1861
def test_gnu_changelog_first(self):
1862
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'first', """\
1863
2005-11-22 John Doe <jdoe@example.com>
1869
def test_gnu_changelog_all(self):
1870
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'all', """\
1871
2005-11-22 John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1878
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1880
def make_branch_with_alternate_ancestries(self, relpath='.'):
1881
# See test_merge_sorted_exclude_ancestry below for the difference with
1882
# bt.per_branch.test_iter_merge_sorted_revision.
1883
# TestIterMergeSortedRevisionsBushyGraph.
1884
# make_branch_with_alternate_ancestries
1885
# and test_merge_sorted_exclude_ancestry
1886
# See the FIXME in assertLogRevnos too.
1887
builder = branchbuilder.BranchBuilder(self.get_transport(relpath))
1899
builder.start_series()
1900
builder.build_snapshot('1', None, [
1901
('add', ('', 'TREE_ROOT', 'directory', '')),])
1902
builder.build_snapshot('1.1.1', ['1'], [])
1903
builder.build_snapshot('2', ['1'], [])
1904
builder.build_snapshot('1.2.1', ['1.1.1'], [])
1905
builder.build_snapshot('1.1.2', ['1.1.1', '1.2.1'], [])
1906
builder.build_snapshot('3', ['2', '1.1.2'], [])
1907
builder.finish_series()
1908
br = builder.get_branch()
1910
self.addCleanup(br.unlock)
1913
def assertLogRevnos(self, expected_revnos, b, start, end,
1914
exclude_common_ancestry, generate_merge_revisions=True):
1915
# FIXME: the layering in log makes it hard to test intermediate levels,
1916
# I wish adding filters with their parameters were easier...
1918
iter_revs = log._calc_view_revisions(
1919
b, start, end, direction='reverse',
1920
generate_merge_revisions=generate_merge_revisions,
1921
exclude_common_ancestry=exclude_common_ancestry)
1922
self.assertEqual(expected_revnos,
1923
[revid for revid, revno, depth in iter_revs])
1925
def test_merge_sorted_exclude_ancestry(self):
1926
b = self.make_branch_with_alternate_ancestries()
1927
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1928
b, '1', '3', exclude_common_ancestry=False)
1929
# '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1930
# it should be mentioned even if merge_sort order will make it appear
1932
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
1933
b, '1.1.1', '3', exclude_common_ancestry=True)
1935
def test_merge_sorted_simple_revnos_exclude_ancestry(self):
1936
b = self.make_branch_with_alternate_ancestries()
1937
self.assertLogRevnos(['3', '2'],
1938
b, '1', '3', exclude_common_ancestry=True,
1939
generate_merge_revisions=False)
1940
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2'],
1941
b, '1', '3', exclude_common_ancestry=True,
1942
generate_merge_revisions=True)