/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_annotate.py

  • Committer: Robert Collins
  • Date: 2010-05-06 23:41:35 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506234135-yivbzczw1sejxnxc
Lock methods on ``Tree``, ``Branch`` and ``Repository`` are now
expected to return an object which can be used to unlock them. This reduces
duplicate code when using cleanups. The previous 'tokens's returned by
``Branch.lock_write`` and ``Repository.lock_write`` are now attributes
on the result of the lock_write. ``repository.RepositoryWriteLockResult``
and ``branch.BranchWriteLockResult`` document this. (Robert Collins)

``log._get_info_for_log_files`` now takes an add_cleanup callable.
(Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2009, 2011 Canonical Ltd
 
1
# Copyright (C) 2006 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
"""Whitebox tests for annotate functionality."""
18
18
 
19
19
import codecs
20
 
from io import BytesIO
 
20
from cStringIO import StringIO
21
21
 
22
 
from .. import (
 
22
from bzrlib import (
23
23
    annotate,
 
24
    conflicts,
 
25
    errors,
24
26
    tests,
25
 
    )
26
 
from ..sixish import (
27
 
    StringIO,
28
 
    )
29
 
from .ui_testing import StringIOWithEncoding
 
27
    trace,
 
28
    )
30
29
 
31
30
 
32
31
def annotation(text):
33
 
    return [tuple(l.split(b' ', 1)) for l in text.splitlines(True)]
34
 
 
35
 
 
36
 
parent_1 = annotation(b"""\
 
32
    return [tuple(l.split(' ', 1)) for l in text.splitlines(True)]
 
33
 
 
34
 
 
35
parent_1 = annotation("""\
37
36
rev1 a
38
37
rev2 b
39
38
rev3 c
42
41
""")
43
42
 
44
43
 
45
 
parent_2 = annotation(b"""\
 
44
parent_2 = annotation("""\
46
45
rev1 a
47
46
rev3 c
48
47
rev4 d
52
51
""")
53
52
 
54
53
 
55
 
expected_2_1 = annotation(b"""\
 
54
expected_2_1 = annotation("""\
56
55
rev1 a
57
56
blahblah b
58
57
rev3 c
69
68
# f: in 2, but not in new, so ignored
70
69
# g: not in 1 or 2, so it goes to blahblah
71
70
# h: only in parent 2, so 2 gets it
72
 
expected_1_2_2 = annotation(b"""\
 
71
expected_1_2_2 = annotation("""\
73
72
rev1 a
74
73
rev2 b
75
74
rev3 c
80
79
""")
81
80
 
82
81
 
83
 
new_1 = b"""\
 
82
new_1 = """\
84
83
a
85
84
b
86
85
c
88
87
e
89
88
""".splitlines(True)
90
89
 
91
 
expected_1 = annotation(b"""\
 
90
expected_1 = annotation("""\
92
91
blahblah a
93
92
blahblah b
94
93
blahblah c
97
96
""")
98
97
 
99
98
 
100
 
new_2 = b"""\
 
99
new_2 = """\
101
100
a
102
101
b
103
102
c
121
120
#  |/
122
121
#  E    # D should supersede A and stay as D (not become E because C references
123
122
#         A)
124
 
duplicate_base = annotation(b"""\
 
123
duplicate_base = annotation("""\
125
124
rev-base first
126
125
rev-base second
127
126
rev-base third
128
127
rev-base fourth-base
129
128
""")
130
129
 
131
 
duplicate_A = annotation(b"""\
 
130
duplicate_A = annotation("""\
132
131
rev-base first
133
132
rev-A alt-second
134
133
rev-base third
135
134
rev-A fourth-A
136
135
""")
137
136
 
138
 
duplicate_B = annotation(b"""\
 
137
duplicate_B = annotation("""\
139
138
rev-base first
140
139
rev-B alt-second
141
140
rev-base third
142
141
rev-B fourth-B
143
142
""")
144
143
 
145
 
duplicate_C = annotation(b"""\
 
144
duplicate_C = annotation("""\
146
145
rev-base first
147
146
rev-A alt-second
148
147
rev-base third
149
148
rev-C fourth-C
150
149
""")
151
150
 
152
 
duplicate_D = annotation(b"""\
 
151
duplicate_D = annotation("""\
153
152
rev-base first
154
153
rev-A alt-second
155
154
rev-base third
156
155
rev-D fourth-D
157
156
""")
158
157
 
159
 
duplicate_E = annotation(b"""\
 
158
duplicate_E = annotation("""\
160
159
rev-base first
161
160
rev-A alt-second
162
161
rev-base third
180
179
        builder = self.make_branch_builder('branch')
181
180
        builder.start_series()
182
181
        self.addCleanup(builder.finish_series)
183
 
        builder.build_snapshot(None, [
184
 
            ('add', ('', b'root-id', 'directory', None)),
185
 
            ('add', ('a', b'a-id', 'file', b'first\n')),
186
 
            ], timestamp=1166046000.00, timezone=0, committer="joe@foo.com",
187
 
            revision_id=b'rev-1')
188
 
        builder.build_snapshot([b'rev-1'], [
189
 
            ('modify', ('a', b'first\nsecond\n')),
190
 
            ], timestamp=1166046001.00, timezone=0, committer="joe@foo.com",
191
 
            revision_id=b'rev-2')
192
 
        builder.build_snapshot([b'rev-1'], [
193
 
            ('modify', ('a', b'first\nthird\n')),
194
 
            ], timestamp=1166046002.00, timezone=0, committer="barry@foo.com",
195
 
            revision_id=b'rev-1_1_1')
196
 
        builder.build_snapshot([b'rev-2', b'rev-1_1_1'], [
197
 
            ('modify', ('a', b'first\nsecond\nthird\n')),
198
 
            ], timestamp=1166046003.00, timezone=0, committer="sal@foo.com",
199
 
            revision_id=b'rev-3')
 
182
        builder.build_snapshot('rev-1', None, [
 
183
            ('add', ('', 'root-id', 'directory', None)),
 
184
            ('add', ('a', 'a-id', 'file', 'first\n')),
 
185
            ], timestamp=1166046000.00, timezone=0, committer="joe@foo.com")
 
186
        builder.build_snapshot('rev-2', ['rev-1'], [
 
187
            ('modify', ('a-id', 'first\nsecond\n')),
 
188
            ], timestamp=1166046001.00, timezone=0, committer="joe@foo.com")
 
189
        builder.build_snapshot('rev-1_1_1', ['rev-1'], [
 
190
            ('modify', ('a-id', 'first\nthird\n')),
 
191
            ], timestamp=1166046002.00, timezone=0, committer="barry@foo.com")
 
192
        builder.build_snapshot('rev-3', ['rev-2', 'rev-1_1_1'], [
 
193
            ('modify', ('a-id', 'first\nsecond\nthird\n')),
 
194
            ], timestamp=1166046003.00, timezone=0, committer="sal@foo.com")
200
195
        return builder
201
196
 
202
197
    def create_deeply_merged_trees(self):
223
218
        rev-6
224
219
        """
225
220
        builder = self.create_merged_trees()
226
 
        builder.build_snapshot([b'rev-1_1_1'], [], revision_id=b'rev-1_1_2')
227
 
        builder.build_snapshot([b'rev-3', b'rev-1_1_2'],
228
 
                               [], revision_id=b'rev-4')
229
 
        builder.build_snapshot([b'rev-1_1_1'], [
230
 
            ('modify', ('a', b'first\nthird\nfourth\n')),
231
 
            ], timestamp=1166046003.00, timezone=0, committer="jerry@foo.com",
232
 
            revision_id=b'rev-1_2_1')
233
 
        builder.build_snapshot([b'rev-1_2_1'], [],
234
 
                               timestamp=1166046004.00, timezone=0, committer="jerry@foo.com",
235
 
                               revision_id=b'rev-1_2_2')
236
 
        builder.build_snapshot([b'rev-4', b'rev-1_2_2'], [
237
 
            ('modify', ('a', b'first\nsecond\nthird\nfourth\n')),
238
 
            ], timestamp=1166046004.00, timezone=0, committer="jerry@foo.com",
239
 
            revision_id=b'rev-5')
240
 
        builder.build_snapshot([b'rev-1_2_1'], [
241
 
            ('modify', ('a', b'first\nthird\nfourth\nfifth\nsixth\n')),
242
 
            ], timestamp=1166046005.00, timezone=0, committer="george@foo.com",
243
 
            revision_id=b'rev-1_3_1')
244
 
        builder.build_snapshot([b'rev-5', b'rev-1_3_1'], [
245
 
            ('modify', ('a',
246
 
                        b'first\nsecond\nthird\nfourth\nfifth\nsixth\n')),
247
 
            ], revision_id=b'rev-6')
 
221
        builder.build_snapshot('rev-1_1_2', ['rev-1_1_1'], [])
 
222
        builder.build_snapshot('rev-4', ['rev-3', 'rev-1_1_2'], [])
 
223
        builder.build_snapshot('rev-1_2_1', ['rev-1_1_1'], [
 
224
            ('modify', ('a-id', 'first\nthird\nfourth\n')),
 
225
            ], timestamp=1166046003.00, timezone=0, committer="jerry@foo.com")
 
226
        builder.build_snapshot('rev-1_2_2', ['rev-1_2_1'], [],
 
227
            timestamp=1166046004.00, timezone=0, committer="jerry@foo.com")
 
228
        builder.build_snapshot('rev-5', ['rev-4', 'rev-1_2_2'], [
 
229
            ('modify', ('a-id', 'first\nsecond\nthird\nfourth\n')),
 
230
            ], timestamp=1166046004.00, timezone=0, committer="jerry@foo.com")
 
231
        builder.build_snapshot('rev-1_3_1', ['rev-1_2_1'], [
 
232
            ('modify', ('a-id', 'first\nthird\nfourth\nfifth\nsixth\n')),
 
233
            ], timestamp=1166046005.00, timezone=0, committer="george@foo.com")
 
234
        builder.build_snapshot('rev-6', ['rev-5', 'rev-1_3_1'], [
 
235
            ('modify', ('a-id',
 
236
                        'first\nsecond\nthird\nfourth\nfifth\nsixth\n')),
 
237
            ])
248
238
        return builder
249
239
 
250
240
    def create_duplicate_lines_tree(self):
251
241
        builder = self.make_branch_builder('branch')
252
242
        builder.start_series()
253
243
        self.addCleanup(builder.finish_series)
254
 
        base_text = b''.join(l for r, l in duplicate_base)
255
 
        a_text = b''.join(l for r, l in duplicate_A)
256
 
        b_text = b''.join(l for r, l in duplicate_B)
257
 
        c_text = b''.join(l for r, l in duplicate_C)
258
 
        d_text = b''.join(l for r, l in duplicate_D)
259
 
        e_text = b''.join(l for r, l in duplicate_E)
260
 
        builder.build_snapshot(None, [
261
 
            ('add', ('', b'root-id', 'directory', None)),
262
 
            ('add', ('file', b'file-id', 'file', base_text)),
263
 
            ], revision_id=b'rev-base')
264
 
        builder.build_snapshot([b'rev-base'], [
265
 
            ('modify', ('file', a_text))],
266
 
            revision_id=b'rev-A')
267
 
        builder.build_snapshot([b'rev-base'], [
268
 
            ('modify', ('file', b_text))],
269
 
            revision_id=b'rev-B')
270
 
        builder.build_snapshot([b'rev-A'], [
271
 
            ('modify', ('file', c_text))],
272
 
            revision_id=b'rev-C')
273
 
        builder.build_snapshot([b'rev-B', b'rev-A'], [
274
 
            ('modify', ('file', d_text))],
275
 
            revision_id=b'rev-D')
276
 
        builder.build_snapshot([b'rev-C', b'rev-D'], [
277
 
            ('modify', ('file', e_text))],
278
 
            revision_id=b'rev-E')
 
244
        base_text = ''.join(l for r, l in duplicate_base)
 
245
        a_text = ''.join(l for r, l in duplicate_A)
 
246
        b_text = ''.join(l for r, l in duplicate_B)
 
247
        c_text = ''.join(l for r, l in duplicate_C)
 
248
        d_text = ''.join(l for r, l in duplicate_D)
 
249
        e_text = ''.join(l for r, l in duplicate_E)
 
250
        builder.build_snapshot('rev-base', None, [
 
251
            ('add', ('', 'root-id', 'directory', None)),
 
252
            ('add', ('file', 'file-id', 'file', base_text)),
 
253
            ])
 
254
        builder.build_snapshot('rev-A', ['rev-base'], [
 
255
            ('modify', ('file-id', a_text))])
 
256
        builder.build_snapshot('rev-B', ['rev-base'], [
 
257
            ('modify', ('file-id', b_text))])
 
258
        builder.build_snapshot('rev-C', ['rev-A'], [
 
259
            ('modify', ('file-id', c_text))])
 
260
        builder.build_snapshot('rev-D', ['rev-B', 'rev-A'], [
 
261
            ('modify', ('file-id', d_text))])
 
262
        builder.build_snapshot('rev-E', ['rev-C', 'rev-D'], [
 
263
            ('modify', ('file-id', e_text))])
279
264
        return builder
280
265
 
281
 
    def assertAnnotateEqualDiff(self, actual, expected):
 
266
    def assertRepoAnnotate(self, expected, repo, file_id, revision_id):
 
267
        """Assert that the revision is properly annotated."""
 
268
        actual = list(repo.revision_tree(revision_id).annotate_iter(file_id))
282
269
        if actual != expected:
283
270
            # Create an easier to understand diff when the lines don't actually
284
271
            # match
285
272
            self.assertEqualDiff(''.join('\t'.join(l) for l in expected),
286
273
                                 ''.join('\t'.join(l) for l in actual))
287
274
 
288
 
    def assertBranchAnnotate(self, expected, branch, path, revision_id,
289
 
                             verbose=False, full=False, show_ids=False):
290
 
        tree = branch.repository.revision_tree(revision_id)
291
 
        to_file = StringIO()
292
 
        annotate.annotate_file_tree(tree, path, to_file,
293
 
                                    verbose=verbose, full=full, show_ids=show_ids, branch=branch)
294
 
        self.assertAnnotateEqualDiff(to_file.getvalue(), expected)
295
 
 
296
 
    def assertRepoAnnotate(self, expected, repo, path, revision_id):
297
 
        """Assert that the revision is properly annotated."""
298
 
        actual = list(repo.revision_tree(revision_id).annotate_iter(path))
299
 
        self.assertAnnotateEqualDiff(actual, expected)
300
 
 
301
275
    def test_annotate_duplicate_lines(self):
302
276
        # XXX: Should this be a per_repository test?
303
277
        builder = self.create_duplicate_lines_tree()
304
278
        repo = builder.get_branch().repository
305
279
        repo.lock_read()
306
280
        self.addCleanup(repo.unlock)
307
 
        self.assertRepoAnnotate(duplicate_base, repo, 'file', b'rev-base')
308
 
        self.assertRepoAnnotate(duplicate_A, repo, 'file', b'rev-A')
309
 
        self.assertRepoAnnotate(duplicate_B, repo, 'file', b'rev-B')
310
 
        self.assertRepoAnnotate(duplicate_C, repo, 'file', b'rev-C')
311
 
        self.assertRepoAnnotate(duplicate_D, repo, 'file', b'rev-D')
312
 
        self.assertRepoAnnotate(duplicate_E, repo, 'file', b'rev-E')
 
281
        self.assertRepoAnnotate(duplicate_base, repo, 'file-id', 'rev-base')
 
282
        self.assertRepoAnnotate(duplicate_A, repo, 'file-id', 'rev-A')
 
283
        self.assertRepoAnnotate(duplicate_B, repo, 'file-id', 'rev-B')
 
284
        self.assertRepoAnnotate(duplicate_C, repo, 'file-id', 'rev-C')
 
285
        self.assertRepoAnnotate(duplicate_D, repo, 'file-id', 'rev-D')
 
286
        self.assertRepoAnnotate(duplicate_E, repo, 'file-id', 'rev-E')
313
287
 
314
288
    def test_annotate_shows_dotted_revnos(self):
315
289
        builder = self.create_merged_trees()
316
290
 
317
 
        self.assertBranchAnnotate('1     joe@foo | first\n'
318
 
                                  '2     joe@foo | second\n'
319
 
                                  '1.1.1 barry@f | third\n',
320
 
                                  builder.get_branch(), 'a', b'rev-3')
 
291
        sio = StringIO()
 
292
        annotate.annotate_file(builder.get_branch(), 'rev-3', 'a-id',
 
293
                               to_file=sio)
 
294
        self.assertEqualDiff('1     joe@foo | first\n'
 
295
                             '2     joe@foo | second\n'
 
296
                             '1.1.1 barry@f | third\n',
 
297
                             sio.getvalue())
321
298
 
322
299
    def test_annotate_limits_dotted_revnos(self):
323
300
        """Annotate should limit dotted revnos to a depth of 12"""
324
301
        builder = self.create_deeply_merged_trees()
325
302
 
326
 
        self.assertBranchAnnotate('1     joe@foo | first\n'
327
 
                                  '2     joe@foo | second\n'
328
 
                                  '1.1.1 barry@f | third\n'
329
 
                                  '1.2.1 jerry@f | fourth\n'
330
 
                                  '1.3.1 george@ | fifth\n'
331
 
                                  '              | sixth\n',
332
 
                                  builder.get_branch(), 'a', b'rev-6',
333
 
                                  verbose=False, full=False)
 
303
        sio = StringIO()
 
304
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
305
                               to_file=sio, verbose=False, full=False)
 
306
        self.assertEqualDiff('1     joe@foo | first\n'
 
307
                             '2     joe@foo | second\n'
 
308
                             '1.1.1 barry@f | third\n'
 
309
                             '1.2.1 jerry@f | fourth\n'
 
310
                             '1.3.1 george@ | fifth\n'
 
311
                             '              | sixth\n',
 
312
                             sio.getvalue())
334
313
 
335
 
        self.assertBranchAnnotate('1     joe@foo | first\n'
336
 
                                  '2     joe@foo | second\n'
337
 
                                  '1.1.1 barry@f | third\n'
338
 
                                  '1.2.1 jerry@f | fourth\n'
339
 
                                  '1.3.1 george@ | fifth\n'
340
 
                                  '1.3.1 george@ | sixth\n',
341
 
                                  builder.get_branch(), 'a', b'rev-6',
342
 
                                  verbose=False, full=True)
 
314
        sio = StringIO()
 
315
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
316
                               to_file=sio, verbose=False, full=True)
 
317
        self.assertEqualDiff('1     joe@foo | first\n'
 
318
                             '2     joe@foo | second\n'
 
319
                             '1.1.1 barry@f | third\n'
 
320
                             '1.2.1 jerry@f | fourth\n'
 
321
                             '1.3.1 george@ | fifth\n'
 
322
                             '1.3.1 george@ | sixth\n',
 
323
                             sio.getvalue())
343
324
 
344
325
        # verbose=True shows everything, the full revno, user id, and date
345
 
        self.assertBranchAnnotate('1     joe@foo.com    20061213 | first\n'
346
 
                                  '2     joe@foo.com    20061213 | second\n'
347
 
                                  '1.1.1 barry@foo.com  20061213 | third\n'
348
 
                                  '1.2.1 jerry@foo.com  20061213 | fourth\n'
349
 
                                  '1.3.1 george@foo.com 20061213 | fifth\n'
350
 
                                  '                              | sixth\n',
351
 
                                  builder.get_branch(), 'a', b'rev-6',
352
 
                                  verbose=True, full=False)
 
326
        sio = StringIO()
 
327
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
328
                               to_file=sio, verbose=True, full=False)
 
329
        self.assertEqualDiff('1     joe@foo.com    20061213 | first\n'
 
330
                             '2     joe@foo.com    20061213 | second\n'
 
331
                             '1.1.1 barry@foo.com  20061213 | third\n'
 
332
                             '1.2.1 jerry@foo.com  20061213 | fourth\n'
 
333
                             '1.3.1 george@foo.com 20061213 | fifth\n'
 
334
                             '                              | sixth\n',
 
335
                             sio.getvalue())
353
336
 
354
 
        self.assertBranchAnnotate('1     joe@foo.com    20061213 | first\n'
355
 
                                  '2     joe@foo.com    20061213 | second\n'
356
 
                                  '1.1.1 barry@foo.com  20061213 | third\n'
357
 
                                  '1.2.1 jerry@foo.com  20061213 | fourth\n'
358
 
                                  '1.3.1 george@foo.com 20061213 | fifth\n'
359
 
                                  '1.3.1 george@foo.com 20061213 | sixth\n',
360
 
                                  builder.get_branch(), 'a', b'rev-6',
361
 
                                  verbose=True, full=True)
 
337
        sio = StringIO()
 
338
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
339
                               to_file=sio, verbose=True, full=True)
 
340
        self.assertEqualDiff('1     joe@foo.com    20061213 | first\n'
 
341
                             '2     joe@foo.com    20061213 | second\n'
 
342
                             '1.1.1 barry@foo.com  20061213 | third\n'
 
343
                             '1.2.1 jerry@foo.com  20061213 | fourth\n'
 
344
                             '1.3.1 george@foo.com 20061213 | fifth\n'
 
345
                             '1.3.1 george@foo.com 20061213 | sixth\n',
 
346
                             sio.getvalue())
362
347
 
363
348
    def test_annotate_uses_branch_context(self):
364
349
        """Dotted revnos should use the Branch context.
368
353
        """
369
354
        builder = self.create_deeply_merged_trees()
370
355
 
371
 
        self.assertBranchAnnotate('1     joe@foo | first\n'
372
 
                                  '1.1.1 barry@f | third\n'
373
 
                                  '1.2.1 jerry@f | fourth\n'
374
 
                                  '1.3.1 george@ | fifth\n'
375
 
                                  '              | sixth\n',
376
 
                                  builder.get_branch(), 'a', b'rev-1_3_1',
377
 
                                  verbose=False, full=False)
 
356
        sio = StringIO()
 
357
        annotate.annotate_file(builder.get_branch(), 'rev-1_3_1', 'a-id',
 
358
                               to_file=sio, verbose=False, full=False)
 
359
        self.assertEqualDiff('1     joe@foo | first\n'
 
360
                             '1.1.1 barry@f | third\n'
 
361
                             '1.2.1 jerry@f | fourth\n'
 
362
                             '1.3.1 george@ | fifth\n'
 
363
                             '              | sixth\n',
 
364
                             sio.getvalue())
378
365
 
379
366
    def test_annotate_show_ids(self):
380
367
        builder = self.create_deeply_merged_trees()
381
368
 
 
369
        sio = StringIO()
 
370
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
371
                               to_file=sio, show_ids=True, full=False)
 
372
 
382
373
        # It looks better with real revision ids :)
383
 
        self.assertBranchAnnotate('    rev-1 | first\n'
384
 
                                  '    rev-2 | second\n'
385
 
                                  'rev-1_1_1 | third\n'
386
 
                                  'rev-1_2_1 | fourth\n'
387
 
                                  'rev-1_3_1 | fifth\n'
388
 
                                  '          | sixth\n',
389
 
                                  builder.get_branch(), 'a', b'rev-6',
390
 
                                  show_ids=True, full=False)
391
 
 
392
 
        self.assertBranchAnnotate('    rev-1 | first\n'
393
 
                                  '    rev-2 | second\n'
394
 
                                  'rev-1_1_1 | third\n'
395
 
                                  'rev-1_2_1 | fourth\n'
396
 
                                  'rev-1_3_1 | fifth\n'
397
 
                                  'rev-1_3_1 | sixth\n',
398
 
                                  builder.get_branch(), 'a', b'rev-6',
399
 
                                  show_ids=True, full=True)
 
374
        self.assertEqualDiff('    rev-1 | first\n'
 
375
                             '    rev-2 | second\n'
 
376
                             'rev-1_1_1 | third\n'
 
377
                             'rev-1_2_1 | fourth\n'
 
378
                             'rev-1_3_1 | fifth\n'
 
379
                             '          | sixth\n',
 
380
                             sio.getvalue())
 
381
 
 
382
        sio = StringIO()
 
383
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
384
                               to_file=sio, show_ids=True, full=True)
 
385
 
 
386
        self.assertEqualDiff('    rev-1 | first\n'
 
387
                             '    rev-2 | second\n'
 
388
                             'rev-1_1_1 | third\n'
 
389
                             'rev-1_2_1 | fourth\n'
 
390
                             'rev-1_3_1 | fifth\n'
 
391
                             'rev-1_3_1 | sixth\n',
 
392
                             sio.getvalue())
400
393
 
401
394
    def test_annotate_unicode_author(self):
402
395
        tree1 = self.make_branch_and_tree('tree1')
403
396
 
404
 
        self.build_tree_contents([('tree1/a', b'adi\xc3\xb3s')])
405
 
        tree1.add(['a'], [b'a-id'])
406
 
        tree1.commit('a', rev_id=b'rev-1',
 
397
        self.build_tree_contents([('tree1/a', 'adi\xc3\xb3s')])
 
398
        tree1.add(['a'], ['a-id'])
 
399
        tree1.commit('a', rev_id='rev-1',
407
400
                     committer=u'Pepe P\xe9rez <pperez@ejemplo.com>',
408
401
                     timestamp=1166046000.00, timezone=0)
409
402
 
410
 
        self.build_tree_contents([('tree1/b', b'bye')])
411
 
        tree1.add(['b'], [b'b-id'])
412
 
        tree1.commit('b', rev_id=b'rev-2',
 
403
        self.build_tree_contents([('tree1/b', 'bye')])
 
404
        tree1.add(['b'], ['b-id'])
 
405
        tree1.commit('b', rev_id='rev-2',
413
406
                     committer=u'p\xe9rez',
414
407
                     timestamp=1166046000.00, timezone=0)
415
408
 
416
409
        tree1.lock_read()
417
410
        self.addCleanup(tree1.unlock)
418
 
 
419
 
        revtree_1 = tree1.branch.repository.revision_tree(b'rev-1')
420
 
        revtree_2 = tree1.branch.repository.revision_tree(b'rev-2')
421
 
 
422
411
        # this passes if no exception is raised
423
412
        to_file = StringIO()
424
 
        annotate.annotate_file_tree(revtree_1, 'a',
425
 
                                    to_file=to_file, branch=tree1.branch)
426
 
 
427
 
        sio = BytesIO()
428
 
        to_file = codecs.getwriter('ascii')(sio, 'replace')
429
 
        annotate.annotate_file_tree(revtree_2, 'b',
430
 
                                    to_file=to_file, branch=tree1.branch)
431
 
        self.assertEqualDiff(b'2   p?rez   | bye\n', sio.getvalue())
432
 
 
433
 
        # test now with unicode file-like
434
 
        to_file = StringIOWithEncoding()
435
 
        annotate.annotate_file_tree(revtree_2, 'b',
436
 
                                    to_file=to_file, branch=tree1.branch)
437
 
        self.assertContainsRe(u'2   p\xe9rez   | bye\n', to_file.getvalue())
 
413
        annotate.annotate_file(tree1.branch, 'rev-1', 'a-id', to_file=to_file)
 
414
 
 
415
        sio = StringIO()
 
416
        to_file = codecs.getwriter('ascii')(sio)
 
417
        to_file.encoding = 'ascii' # codecs does not set it
 
418
        annotate.annotate_file(tree1.branch, 'rev-2', 'b-id', to_file=to_file)
 
419
        self.assertEqualDiff('2   p?rez   | bye\n', sio.getvalue())
 
420
 
 
421
        # test now with to_file.encoding = None
 
422
        to_file = tests.StringIOWrapper()
 
423
        to_file.encoding = None
 
424
        annotate.annotate_file(tree1.branch, 'rev-2', 'b-id', to_file=to_file)
 
425
        self.assertContainsRe('2   p.rez   | bye\n', to_file.getvalue())
 
426
 
 
427
        # and when it does not exist
 
428
        to_file = StringIO()
 
429
        annotate.annotate_file(tree1.branch, 'rev-2', 'b-id', to_file=to_file)
 
430
        self.assertContainsRe('2   p.rez   | bye\n', to_file.getvalue())
438
431
 
439
432
    def test_annotate_author_or_committer(self):
440
433
        tree1 = self.make_branch_and_tree('tree1')
441
434
 
442
 
        self.build_tree_contents([('tree1/a', b'hello')])
443
 
        tree1.add(['a'], [b'a-id'])
444
 
        tree1.commit('a', rev_id=b'rev-1',
 
435
        self.build_tree_contents([('tree1/a', 'hello')])
 
436
        tree1.add(['a'], ['a-id'])
 
437
        tree1.commit('a', rev_id='rev-1',
445
438
                     committer='Committer <committer@example.com>',
446
439
                     timestamp=1166046000.00, timezone=0)
447
440
 
448
 
        self.build_tree_contents([('tree1/b', b'bye')])
449
 
        tree1.add(['b'], [b'b-id'])
450
 
        tree1.commit('b', rev_id=b'rev-2',
 
441
        self.build_tree_contents([('tree1/b', 'bye')])
 
442
        tree1.add(['b'], ['b-id'])
 
443
        tree1.commit('b', rev_id='rev-2',
451
444
                     committer='Committer <committer@example.com>',
452
445
                     authors=['Author <author@example.com>'],
453
446
                     timestamp=1166046000.00, timezone=0)
454
447
 
455
448
        tree1.lock_read()
456
449
        self.addCleanup(tree1.unlock)
457
 
 
458
 
        self.assertBranchAnnotate('1   committ | hello\n', tree1.branch,
459
 
                                  'a', b'rev-1')
460
 
 
461
 
        self.assertBranchAnnotate('2   author@ | bye\n', tree1.branch,
462
 
                                  'b', b'rev-2')
 
450
        to_file = StringIO()
 
451
        annotate.annotate_file(tree1.branch, 'rev-1', 'a-id', to_file=to_file)
 
452
        self.assertEqual('1   committ | hello\n', to_file.getvalue())
 
453
 
 
454
        to_file = StringIO()
 
455
        annotate.annotate_file(tree1.branch, 'rev-2', 'b-id', to_file=to_file)
 
456
        self.assertEqual('2   author@ | bye\n', to_file.getvalue())
463
457
 
464
458
 
465
459
class TestReannotate(tests.TestCase):
467
461
    def annotateEqual(self, expected, parents, newlines, revision_id,
468
462
                      blocks=None):
469
463
        annotate_list = list(annotate.reannotate(parents, newlines,
470
 
                                                 revision_id, blocks))
 
464
                             revision_id, blocks))
471
465
        self.assertEqual(len(expected), len(annotate_list))
472
466
        for e, a in zip(expected, annotate_list):
473
467
            self.assertEqual(e, a)
474
468
 
475
469
    def test_reannotate(self):
476
 
        self.annotateEqual(parent_1, [parent_1], new_1, b'blahblah')
477
 
        self.annotateEqual(expected_2_1, [parent_2], new_1, b'blahblah')
 
470
        self.annotateEqual(parent_1, [parent_1], new_1, 'blahblah')
 
471
        self.annotateEqual(expected_2_1, [parent_2], new_1, 'blahblah')
478
472
        self.annotateEqual(expected_1_2_2, [parent_1, parent_2], new_2,
479
 
                           b'blahblah')
 
473
                           'blahblah')
480
474
 
481
475
    def test_reannotate_no_parents(self):
482
 
        self.annotateEqual(expected_1, [], new_1, b'blahblah')
 
476
        self.annotateEqual(expected_1, [], new_1, 'blahblah')
483
477
 
484
478
    def test_reannotate_left_matching_blocks(self):
485
479
        """Ensure that left_matching_blocks has an impact.
487
481
        In this case, the annotation is ambiguous, so the hint isn't actually
488
482
        lying.
489
483
        """
490
 
        parent = [(b'rev1', b'a\n')]
491
 
        new_text = [b'a\n', b'a\n']
 
484
        parent = [('rev1', 'a\n')]
 
485
        new_text = ['a\n', 'a\n']
492
486
        blocks = [(0, 0, 1), (1, 2, 0)]
493
 
        self.annotateEqual([(b'rev1', b'a\n'), (b'rev2', b'a\n')], [parent],
494
 
                           new_text, b'rev2', blocks)
 
487
        self.annotateEqual([('rev1', 'a\n'), ('rev2', 'a\n')], [parent],
 
488
                           new_text, 'rev2', blocks)
495
489
        blocks = [(0, 1, 1), (1, 2, 0)]
496
 
        self.annotateEqual([(b'rev2', b'a\n'), (b'rev1', b'a\n')], [parent],
497
 
                           new_text, b'rev2', blocks)
 
490
        self.annotateEqual([('rev2', 'a\n'), ('rev1', 'a\n')], [parent],
 
491
                           new_text, 'rev2', blocks)