57
45
self.assertTrue('message:\n message2\n' in self.full_log)
58
46
self.assertTrue('message:\n message3\n' in self.full_log)
60
log = self.run_bzr("log -r 1..")[0]
61
self.assertEqualDiff(log, self.full_log)
48
log = self.runbzr("log -r 1..")[0]
49
self.assertEquals(log, self.full_log)
63
51
def test_log_null_begin_revspec(self):
65
log = self.run_bzr("log -r ..3")[0]
66
self.assertEqualDiff(self.full_log, log)
53
log = self.runbzr("log -r ..3")[0]
54
self.assertEquals(self.full_log, log)
68
56
def test_log_null_both_revspecs(self):
70
log = self.run_bzr("log -r ..")[0]
71
self.assertEqualDiff(self.full_log, log)
73
def test_log_zero_revspec(self):
75
self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
78
def test_log_zero_begin_revspec(self):
80
self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
83
def test_log_zero_end_revspec(self):
85
self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
88
def test_log_unsupported_timezone(self):
90
self.run_bzr_error('bzr: ERROR: Unsupported timezone format "foo", '
91
'options are "utc", "original", "local".',
92
['log', '--timezone', 'foo'])
58
log = self.runbzr("log -r ..")[0]
59
self.assertEquals(self.full_log, log)
94
61
def test_log_negative_begin_revspec_full_log(self):
96
log = self.run_bzr("log -r -3..")[0]
97
self.assertEqualDiff(self.full_log, log)
63
log = self.runbzr("log -r -3..")[0]
64
self.assertEquals(self.full_log, log)
99
66
def test_log_negative_both_revspec_full_log(self):
101
log = self.run_bzr("log -r -3..-1")[0]
102
self.assertEqualDiff(self.full_log, log)
68
log = self.runbzr("log -r -3..-1")[0]
69
self.assertEquals(self.full_log, log)
104
71
def test_log_negative_both_revspec_partial(self):
106
log = self.run_bzr("log -r -3..-2")[0]
73
log = self.runbzr("log -r -3..-2")[0]
107
74
self.assertTrue('revno: 1\n' in log)
108
75
self.assertTrue('revno: 2\n' in log)
109
76
self.assertTrue('revno: 3\n' not in log)
111
78
def test_log_negative_begin_revspec(self):
113
log = self.run_bzr("log -r -2..")[0]
80
log = self.runbzr("log -r -2..")[0]
114
81
self.assertTrue('revno: 1\n' not in log)
115
82
self.assertTrue('revno: 2\n' in log)
116
83
self.assertTrue('revno: 3\n' in log)
118
def test_log_positive_revspecs(self):
120
log = self.run_bzr("log -r 1..3")[0]
121
self.assertEqualDiff(self.full_log, log)
123
def test_log_reversed_revspecs(self):
125
self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
126
'the end revision.\n',),
129
def test_log_revno_n_path(self):
130
self._prepare(path='branch1')
131
self._prepare(path='branch2')
132
log = self.run_bzr("log -r revno:2:branch1..revno:3:branch2",
134
log = self.run_bzr("log -r revno:1:branch2..revno:3:branch2")[0]
135
self.assertEqualDiff(self.full_log, log)
136
log = self.run_bzr("log -r revno:1:branch2")[0]
137
self.assertTrue('revno: 1\n' in log)
138
self.assertTrue('revno: 2\n' not in log)
139
self.assertTrue('branch nick: branch2\n' in log)
140
self.assertTrue('branch nick: branch1\n' not in log)
142
def test_log_change_revno(self):
144
expected_log = self.run_bzr("log -r 1")[0]
145
log = self.run_bzr("log -c 1")[0]
146
self.assertEqualDiff(expected_log, log)
148
def test_log_change_single_revno(self):
150
self.run_bzr_error('bzr: ERROR: Option --change does not'
151
' accept revision ranges',
152
['log', '--change', '2..3'])
154
def test_log_change_incompatible_with_revision(self):
156
self.run_bzr_error('bzr: ERROR: --revision and --change'
157
' are mutually exclusive',
158
['log', '--change', '2', '--revision', '3'])
160
def test_log_nonexistent_file(self):
161
# files that don't exist in either the basis tree or working tree
162
# should give an error
163
wt = self.make_branch_and_tree('.')
164
out, err = self.run_bzr('log does-not-exist', retcode=3)
165
self.assertContainsRe(
166
err, 'Path does not have any revision history: does-not-exist')
168
def test_log_with_tags(self):
169
tree = self._prepare(format='dirstate-tags')
171
branch.tags.set_tag('tag1', branch.get_rev_id(1))
172
branch.tags.set_tag('tag1.1', branch.get_rev_id(1))
173
branch.tags.set_tag('tag3', branch.last_revision())
175
log = self.run_bzr("log -r-1")[0]
176
self.assertTrue('tags: tag3' in log)
178
log = self.run_bzr("log -r1")[0]
179
# I guess that we can't know the order of tags in the output
180
# since dicts are unordered, need to check both possibilities
181
self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)')
183
def test_merged_log_with_tags(self):
184
branch1_tree = self._prepare(path='branch1', format='dirstate-tags')
185
branch1 = branch1_tree.branch
186
branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
187
branch1_tree.commit(message='foobar', allow_pointless=True)
188
branch1.tags.set_tag('tag1', branch1.last_revision())
190
self.run_bzr('merge ../branch1') # tags don't propagate otherwise
191
branch2_tree.commit(message='merge branch 1')
192
log = self.run_bzr("log -r-1")[0]
193
self.assertContainsRe(log, r' tags: tag1')
194
log = self.run_bzr("log -r3.1.1")[0]
195
self.assertContainsRe(log, r'tags: tag1')
197
def test_log_limit(self):
198
tree = self.make_branch_and_tree('.')
199
# We want more commits than our batch size starts at
200
for pos in range(10):
201
tree.commit("%s" % pos)
202
log = self.run_bzr("log --limit 2")[0]
203
self.assertNotContainsRe(log, r'revno: 1\n')
204
self.assertNotContainsRe(log, r'revno: 2\n')
205
self.assertNotContainsRe(log, r'revno: 3\n')
206
self.assertNotContainsRe(log, r'revno: 4\n')
207
self.assertNotContainsRe(log, r'revno: 5\n')
208
self.assertNotContainsRe(log, r'revno: 6\n')
209
self.assertNotContainsRe(log, r'revno: 7\n')
210
self.assertNotContainsRe(log, r'revno: 8\n')
211
self.assertContainsRe(log, r'revno: 9\n')
212
self.assertContainsRe(log, r'revno: 10\n')
214
def test_log_limit_short(self):
216
log = self.run_bzr("log -l 2")[0]
217
self.assertNotContainsRe(log, r'revno: 1\n')
218
self.assertContainsRe(log, r'revno: 2\n')
219
self.assertContainsRe(log, r'revno: 3\n')
222
class TestLogMerges(TestCaseWithoutPropsHandler):
225
parent_tree = self.make_branch_and_tree('parent')
226
parent_tree.commit(message='first post', allow_pointless=True)
227
child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
228
child_tree.commit(message='branch 1', allow_pointless=True)
230
child_tree.bzrdir.sprout('smallerchild').open_workingtree()
231
smaller_tree.commit(message='branch 2', allow_pointless=True)
232
child_tree.merge_from_branch(smaller_tree.branch)
233
child_tree.commit(message='merge branch 2')
234
parent_tree.merge_from_branch(child_tree.branch)
235
parent_tree.commit(message='merge branch 1')
85
def test_log_postive_revspecs(self):
87
log = self.runbzr("log -r 1..3")[0]
88
self.assertEquals(self.full_log, log)
91
class TestLogMerges(ExternalBase):
238
93
def test_merges_are_indented_by_level(self):
94
self.build_tree(['parent/'])
95
self.run_bzr('init', 'parent')
96
self.run_bzr('commit', '-m', 'first post', '--unchanged', 'parent')
97
self.run_bzr('branch', 'parent', 'child')
98
self.run_bzr('commit', '-m', 'branch 1', '--unchanged', 'child')
99
self.run_bzr('branch', 'child', 'smallerchild')
100
self.run_bzr('commit', '-m', 'branch 2', '--unchanged', 'smallerchild')
102
self.run_bzr('merge', '../smallerchild')
103
self.run_bzr('commit', '-m', 'merge branch 2')
104
os.chdir('../parent')
105
self.run_bzr('merge', '../child')
106
self.run_bzr('commit', '-m', 'merge branch 1')
240
107
out,err = self.run_bzr('log')
241
self.assertEqual('', err)
242
log = normalize_log(out)
243
self.assertEqualDiff(log, """\
244
------------------------------------------------------------
246
committer: Lorem Ipsum <test@example.com>
251
------------------------------------------------------------
253
committer: Lorem Ipsum <test@example.com>
258
------------------------------------------------------------
260
committer: Lorem Ipsum <test@example.com>
261
branch nick: smallerchild
265
------------------------------------------------------------
267
committer: Lorem Ipsum <test@example.com>
272
------------------------------------------------------------
274
committer: Lorem Ipsum <test@example.com>
281
def test_merges_single_merge_rev(self):
283
out,err = self.run_bzr('log -r1.1.2')
284
self.assertEqual('', err)
285
log = normalize_log(out)
286
self.assertEqualDiff(log, """\
287
------------------------------------------------------------
289
committer: Lorem Ipsum <test@example.com>
294
------------------------------------------------------------
296
committer: Lorem Ipsum <test@example.com>
297
branch nick: smallerchild
303
def test_merges_partial_range(self):
305
out,err = self.run_bzr('log -r1.1.1..1.1.2')
306
self.assertEqual('', err)
307
log = normalize_log(out)
308
self.assertEqualDiff(log, """\
309
------------------------------------------------------------
311
committer: Lorem Ipsum <test@example.com>
316
------------------------------------------------------------
318
committer: Lorem Ipsum <test@example.com>
319
branch nick: smallerchild
323
------------------------------------------------------------
325
committer: Lorem Ipsum <test@example.com>
332
def test_merges_nonsupporting_formatter(self):
334
err_msg = 'Selected log formatter only supports mainline revisions.'
335
# The single revision case is tested in the core tests
336
# since all standard formatters support single merge revisions.
337
out,err = self.run_bzr('log --short -r1..1.1.2', retcode=3)
338
self.assertContainsRe(err, err_msg)
339
out,err = self.run_bzr('log --short -r1.1.1..1.1.2', retcode=3)
340
self.assertContainsRe(err, err_msg)
343
class TestLogEncodings(TestCaseInTempDir):
346
_message = u'Message with \xb5'
348
# Encodings which can encode mu
353
'cp437', # Common windows encoding
354
'cp1251', # Alexander Belchenko's windows encoding
355
'cp1258', # Common windows encoding
357
# Encodings which cannot encode mu
365
TestCaseInTempDir.setUp(self)
366
self.user_encoding = osutils._cached_user_encoding
369
osutils._cached_user_encoding = self.user_encoding
370
TestCaseInTempDir.tearDown(self)
372
def create_branch(self):
375
open('a', 'wb').write('some stuff\n')
377
bzr(['commit', '-m', self._message])
379
def try_encoding(self, encoding, fail=False):
382
self.assertRaises(UnicodeEncodeError,
383
self._mu.encode, encoding)
384
encoded_msg = self._message.encode(encoding, 'replace')
386
encoded_msg = self._message.encode(encoding)
388
old_encoding = osutils._cached_user_encoding
389
# This test requires that 'run_bzr' uses the current
390
# bzrlib, because we override user_encoding, and expect
393
osutils._cached_user_encoding = 'ascii'
394
# We should be able to handle any encoding
395
out, err = bzr('log', encoding=encoding)
397
# Make sure we wrote mu as we expected it to exist
398
self.assertNotEqual(-1, out.find(encoded_msg))
399
out_unicode = out.decode(encoding)
400
self.assertNotEqual(-1, out_unicode.find(self._message))
402
self.assertNotEqual(-1, out.find('Message with ?'))
404
osutils._cached_user_encoding = old_encoding
406
def test_log_handles_encoding(self):
409
for encoding in self.good_encodings:
410
self.try_encoding(encoding)
412
def test_log_handles_bad_encoding(self):
415
for encoding in self.bad_encodings:
416
self.try_encoding(encoding, fail=True)
418
def test_stdout_encoding(self):
420
osutils._cached_user_encoding = "cp1251"
423
self.build_tree(['a'])
425
bzr(['commit', '-m', u'\u0422\u0435\u0441\u0442'])
426
stdout, stderr = self.run_bzr('log', encoding='cp866')
428
message = stdout.splitlines()[-1]
430
# explanation of the check:
431
# u'\u0422\u0435\u0441\u0442' is word 'Test' in russian
432
# in cp866 encoding this is string '\x92\xa5\xe1\xe2'
433
# in cp1251 encoding this is string '\xd2\xe5\xf1\xf2'
434
# This test should check that output of log command
435
# encoded to sys.stdout.encoding
436
test_in_cp866 = '\x92\xa5\xe1\xe2'
437
test_in_cp1251 = '\xd2\xe5\xf1\xf2'
438
# Make sure the log string is encoded in cp866
439
self.assertEquals(test_in_cp866, message[2:])
440
# Make sure the cp1251 string is not found anywhere
441
self.assertEquals(-1, stdout.find(test_in_cp1251))
444
class TestLogFile(TestCaseWithTransport):
446
def test_log_local_branch_file(self):
447
"""We should be able to log files in local treeless branches"""
448
tree = self.make_branch_and_tree('tree')
449
self.build_tree(['tree/file'])
451
tree.commit('revision 1')
452
tree.bzrdir.destroy_workingtree()
453
self.run_bzr('log tree/file')
455
def test_log_file(self):
456
"""The log for a particular file should only list revs for that file"""
457
tree = self.make_branch_and_tree('parent')
458
self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
460
tree.commit('add file1')
462
tree.commit('add file2')
464
tree.commit('add file3')
465
child_tree = tree.bzrdir.sprout('child').open_workingtree()
466
self.build_tree_contents([('child/file2', 'hello')])
467
child_tree.commit(message='branch 1')
468
tree.merge_from_branch(child_tree.branch)
469
tree.commit(message='merge child branch')
471
log = self.run_bzr('log file1')[0]
472
self.assertContainsRe(log, 'revno: 1\n')
473
self.assertNotContainsRe(log, 'revno: 2\n')
474
self.assertNotContainsRe(log, 'revno: 3\n')
475
self.assertNotContainsRe(log, 'revno: 3.1.1\n')
476
self.assertNotContainsRe(log, 'revno: 4\n')
477
log = self.run_bzr('log file2')[0]
478
self.assertNotContainsRe(log, 'revno: 1\n')
479
self.assertContainsRe(log, 'revno: 2\n')
480
self.assertNotContainsRe(log, 'revno: 3\n')
481
self.assertContainsRe(log, 'revno: 3.1.1\n')
482
self.assertContainsRe(log, 'revno: 4\n')
483
log = self.run_bzr('log file3')[0]
484
self.assertNotContainsRe(log, 'revno: 1\n')
485
self.assertNotContainsRe(log, 'revno: 2\n')
486
self.assertContainsRe(log, 'revno: 3\n')
487
self.assertNotContainsRe(log, 'revno: 3.1.1\n')
488
self.assertNotContainsRe(log, 'revno: 4\n')
489
log = self.run_bzr('log -r3.1.1 file2')[0]
490
self.assertNotContainsRe(log, 'revno: 1\n')
491
self.assertNotContainsRe(log, 'revno: 2\n')
492
self.assertNotContainsRe(log, 'revno: 3\n')
493
self.assertContainsRe(log, 'revno: 3.1.1\n')
494
self.assertNotContainsRe(log, 'revno: 4\n')
495
log = self.run_bzr('log -r4 file2')[0]
496
self.assertNotContainsRe(log, 'revno: 1\n')
497
self.assertNotContainsRe(log, 'revno: 2\n')
498
self.assertNotContainsRe(log, 'revno: 3\n')
499
self.assertContainsRe(log, 'revno: 3.1.1\n')
500
self.assertContainsRe(log, 'revno: 4\n')
501
log = self.run_bzr('log -r3.. file2')[0]
502
self.assertNotContainsRe(log, 'revno: 1\n')
503
self.assertNotContainsRe(log, 'revno: 2\n')
504
self.assertNotContainsRe(log, 'revno: 3\n')
505
self.assertContainsRe(log, 'revno: 3.1.1\n')
506
self.assertContainsRe(log, 'revno: 4\n')
507
log = self.run_bzr('log -r..3 file2')[0]
508
self.assertNotContainsRe(log, 'revno: 1\n')
509
self.assertContainsRe(log, 'revno: 2\n')
510
self.assertNotContainsRe(log, 'revno: 3\n')
511
self.assertNotContainsRe(log, 'revno: 3.1.1\n')
512
self.assertNotContainsRe(log, 'revno: 4\n')
108
# the log will look something like:
109
# self.assertEqual("""\
110
#------------------------------------------------------------
112
#committer: Robert Collins <foo@example.com>
114
#timestamp: Tue 2006-03-28 22:31:40 +1100
117
# ------------------------------------------------------------
118
# merged: foo@example.com-20060328113140-91f43cfb46dc2863
119
# committer: Robert Collins <foo@example.com>
121
# timestamp: Tue 2006-03-28 22:31:40 +1100
124
# ------------------------------------------------------------
125
# merged: foo@example.com-20060328113140-1ba24f850a0ef573
126
# committer: Robert Collins <foo@example.com>
127
# branch nick: smallerchild
128
# timestamp: Tue 2006-03-28 22:31:40 +1100
131
# ------------------------------------------------------------
132
# merged: foo@example.com-20060328113140-5749a4757a8ac792
133
# committer: Robert Collins <foo@example.com>
135
# timestamp: Tue 2006-03-28 22:31:40 +1100
138
#------------------------------------------------------------
140
#committer: Robert Collins <foo@example.com>
142
#timestamp: Tue 2006-03-28 22:31:39 +1100
146
# but we dont have a nice pattern matcher hooked up yet, so:
147
# we check for the indenting of the commit message:
148
self.assertTrue(' merge branch 1' in out)
149
self.assertTrue(' merge branch 2' in out)
150
self.assertTrue(' branch 2' in out)
151
self.assertTrue(' branch 1' in out)
152
self.assertTrue(' first post' in out)
153
self.assertEqual('', err)