/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: Martin Pool
  • Date: 2007-10-03 08:06:44 UTC
  • mto: This revision was merged to the branch mainline in revision 2901.
  • Revision ID: mbp@sourcefrog.net-20071003080644-oivy0gkg98sex0ed
Avoid internal error tracebacks on failure to lock on readonly transport (#129701).

Add new LockFailed, which doesn't imply that we failed to get it because of
contention.  Raise this if we fail to create the pending or lock directories
because of Transport errors.

UnlockableTransport is not an internal error.

ReadOnlyLockError has a message which didn't match its name or usage; it's now
deprecated and callers are updated to use LockFailed which is more appropriate.

Add zero_ninetytwo deprecation symbol.

Unify assertMatchesRe with TestCase.assertContainsRe.

When the constructor is deprecated, just say that the class is deprecated, not
the __init__ method - this works better with applyDeprecated in tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
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
16
16
 
17
17
"""Whitebox tests for annotate functionality."""
18
18
 
107
107
""".splitlines(True)
108
108
 
109
109
 
110
 
# For the 'duplicate' series, both sides introduce the same change, which then
111
 
# gets merged around. The last-modified should properly reflect this.
112
 
# We always change the fourth line so that the file is properly tracked as
113
 
# being modified in each revision. In reality, this probably would happen over
114
 
# many revisions, and it would be a different line that changes.
115
 
# BASE
116
 
#  |\
117
 
#  A B  # line should be annotated as new for A and B
118
 
#  |\|
119
 
#  C D  # line should 'converge' and say A
120
 
#  |/
121
 
#  E    # D should supersede A and stay as D (not become E because C references
122
 
#         A)
123
 
duplicate_base = annotation("""\
124
 
rev-base first
125
 
rev-base second
126
 
rev-base third
127
 
rev-base fourth-base
128
 
""")
129
 
 
130
 
duplicate_A = annotation("""\
131
 
rev-base first
132
 
rev-A alt-second
133
 
rev-base third
134
 
rev-A fourth-A
135
 
""")
136
 
 
137
 
duplicate_B = annotation("""\
138
 
rev-base first
139
 
rev-B alt-second
140
 
rev-base third
141
 
rev-B fourth-B
142
 
""")
143
 
 
144
 
duplicate_C = annotation("""\
145
 
rev-base first
146
 
rev-A alt-second
147
 
rev-base third
148
 
rev-C fourth-C
149
 
""")
150
 
 
151
 
duplicate_D = annotation("""\
152
 
rev-base first
153
 
rev-A alt-second
154
 
rev-base third
155
 
rev-D fourth-D
156
 
""")
157
 
 
158
 
duplicate_E = annotation("""\
159
 
rev-base first
160
 
rev-A alt-second
161
 
rev-base third
162
 
rev-E fourth-E
163
 
""")
164
 
 
165
 
 
166
110
class TestAnnotate(tests.TestCaseWithTransport):
167
111
 
168
112
    def create_merged_trees(self):
176
120
         |
177
121
        rev-3
178
122
        """
179
 
        builder = self.make_branch_builder('branch')
180
 
        builder.start_series()
181
 
        self.addCleanup(builder.finish_series)
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")
195
 
        return builder
 
123
 
 
124
        tree1 = self.make_branch_and_tree('tree1')
 
125
        self.build_tree_contents([('tree1/a', 'first\n')])
 
126
        tree1.add(['a'], ['a-id'])
 
127
        tree1.commit('a', rev_id='rev-1',
 
128
                     committer="joe@foo.com",
 
129
                     timestamp=1166046000.00, timezone=0)
 
130
 
 
131
        tree2 = tree1.bzrdir.clone('tree2').open_workingtree()
 
132
 
 
133
        self.build_tree_contents([('tree1/a', 'first\nsecond\n')])
 
134
        tree1.commit('b', rev_id='rev-2',
 
135
                     committer='joe@foo.com',
 
136
                     timestamp=1166046001.00, timezone=0)
 
137
 
 
138
        self.build_tree_contents([('tree2/a', 'first\nthird\n')])
 
139
        tree2.commit('c', rev_id='rev-1_1_1',
 
140
                     committer="barry@foo.com",
 
141
                     timestamp=1166046002.00, timezone=0)
 
142
 
 
143
        num_conflicts = tree1.merge_from_branch(tree2.branch)
 
144
        self.assertEqual(1, num_conflicts)
 
145
 
 
146
        self.build_tree_contents([('tree1/a',
 
147
                                 'first\nsecond\nthird\n')])
 
148
        tree1.set_conflicts(conflicts.ConflictList())
 
149
        tree1.commit('merge 2', rev_id='rev-3',
 
150
                     committer='sal@foo.com',
 
151
                     timestamp=1166046003.00, timezone=0)
 
152
        return tree1, tree2
196
153
 
197
154
    def create_deeply_merged_trees(self):
198
155
        """Create some trees with a more complex merge history.
203
160
         |      |          |
204
161
         +------+          |
205
162
         |      |          |
206
 
        rev-3  rev-1_1_2  rev-1_2_1 ------+
 
163
        rev-3  rev-1_1_2  rev-1_1_1_1_1 --+
207
164
         |      |          |              |
208
165
         +------+          |              |
209
166
         |                 |              |
210
 
        rev-4             rev-1_2_2  rev-1_3_1
 
167
        rev-4             rev-1_1_1_1_2  rev-1_1_1_1_1_1_1
211
168
         |                 |              |
212
169
         +-----------------+              |
213
170
         |                                |
217
174
         |
218
175
        rev-6
219
176
        """
220
 
        builder = self.create_merged_trees()
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
 
            ])
238
 
        return builder
239
 
 
240
 
    def create_duplicate_lines_tree(self):
241
 
        builder = self.make_branch_builder('branch')
242
 
        builder.start_series()
243
 
        self.addCleanup(builder.finish_series)
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))])
264
 
        return builder
265
 
 
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))
269
 
        if actual != expected:
270
 
            # Create an easier to understand diff when the lines don't actually
271
 
            # match
272
 
            self.assertEqualDiff(''.join('\t'.join(l) for l in expected),
273
 
                                 ''.join('\t'.join(l) for l in actual))
274
 
 
275
 
    def test_annotate_duplicate_lines(self):
276
 
        # XXX: Should this be a per_repository test?
277
 
        builder = self.create_duplicate_lines_tree()
278
 
        repo = builder.get_branch().repository
279
 
        repo.lock_read()
280
 
        self.addCleanup(repo.unlock)
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')
 
177
        tree1, tree2 = self.create_merged_trees()
 
178
 
 
179
        tree3 = tree2.bzrdir.clone('tree3').open_workingtree()
 
180
 
 
181
        tree2.commit('noop', rev_id='rev-1_1_2')
 
182
        self.assertEqual(0, tree1.merge_from_branch(tree2.branch))
 
183
        tree1.commit('noop merge', rev_id='rev-4')
 
184
 
 
185
        self.build_tree_contents([('tree3/a', 'first\nthird\nfourth\n')])
 
186
        tree3.commit('four', rev_id='rev-1_1_1_1_1',
 
187
                     committer='jerry@foo.com',
 
188
                     timestamp=1166046003.00, timezone=0)
 
189
 
 
190
        tree4 = tree3.bzrdir.clone('tree4').open_workingtree()
 
191
 
 
192
        tree3.commit('noop', rev_id='rev-1_1_1_1_2',
 
193
                     committer='jerry@foo.com',
 
194
                     timestamp=1166046004.00, timezone=0)
 
195
        self.assertEqual(0, tree1.merge_from_branch(tree3.branch))
 
196
        tree1.commit('merge four', rev_id='rev-5')
 
197
 
 
198
        self.build_tree_contents([('tree4/a',
 
199
                                   'first\nthird\nfourth\nfifth\nsixth\n')])
 
200
        tree4.commit('five and six', rev_id='rev-1_1_1_1_1_1_1',
 
201
                     committer='george@foo.com',
 
202
                     timestamp=1166046005.00, timezone=0)
 
203
        self.assertEqual(0, tree1.merge_from_branch(tree4.branch))
 
204
        tree1.commit('merge five and six', rev_id='rev-6')
 
205
        return tree1
287
206
 
288
207
    def test_annotate_shows_dotted_revnos(self):
289
 
        builder = self.create_merged_trees()
 
208
        tree1, tree2 = self.create_merged_trees()
290
209
 
291
210
        sio = StringIO()
292
 
        annotate.annotate_file(builder.get_branch(), 'rev-3', 'a-id',
 
211
        annotate.annotate_file(tree1.branch, 'rev-3', 'a-id',
293
212
                               to_file=sio)
294
213
        self.assertEqualDiff('1     joe@foo | first\n'
295
214
                             '2     joe@foo | second\n'
298
217
 
299
218
    def test_annotate_limits_dotted_revnos(self):
300
219
        """Annotate should limit dotted revnos to a depth of 12"""
301
 
        builder = self.create_deeply_merged_trees()
 
220
        tree1 = self.create_deeply_merged_trees()
302
221
 
303
222
        sio = StringIO()
304
 
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
223
        annotate.annotate_file(tree1.branch, 'rev-6', 'a-id',
305
224
                               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',
 
225
        self.assertEqualDiff('1            joe@foo | first\n'
 
226
                             '2            joe@foo | second\n'
 
227
                             '1.1.1        barry@f | third\n'
 
228
                             '1.1.1.1.1    jerry@f | fourth\n'
 
229
                             '1.1.1.1.1.1> george@ | fifth\n'
 
230
                             '                     | sixth\n',
312
231
                             sio.getvalue())
313
232
 
314
233
        sio = StringIO()
315
 
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
234
        annotate.annotate_file(tree1.branch, 'rev-6', 'a-id',
316
235
                               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',
 
236
        self.assertEqualDiff('1            joe@foo | first\n'
 
237
                             '2            joe@foo | second\n'
 
238
                             '1.1.1        barry@f | third\n'
 
239
                             '1.1.1.1.1    jerry@f | fourth\n'
 
240
                             '1.1.1.1.1.1> george@ | fifth\n'
 
241
                             '1.1.1.1.1.1> george@ | sixth\n',
323
242
                             sio.getvalue())
324
243
 
325
244
        # verbose=True shows everything, the full revno, user id, and date
326
245
        sio = StringIO()
327
 
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
246
        annotate.annotate_file(tree1.branch, 'rev-6', 'a-id',
328
247
                               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',
 
248
        self.assertEqualDiff('1             joe@foo.com    20061213 | first\n'
 
249
                             '2             joe@foo.com    20061213 | second\n'
 
250
                             '1.1.1         barry@foo.com  20061213 | third\n'
 
251
                             '1.1.1.1.1     jerry@foo.com  20061213 | fourth\n'
 
252
                             '1.1.1.1.1.1.1 george@foo.com 20061213 | fifth\n'
 
253
                             '                                      | sixth\n',
335
254
                             sio.getvalue())
336
255
 
337
256
        sio = StringIO()
338
 
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
257
        annotate.annotate_file(tree1.branch, 'rev-6', 'a-id',
339
258
                               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',
 
259
        self.assertEqualDiff('1             joe@foo.com    20061213 | first\n'
 
260
                             '2             joe@foo.com    20061213 | second\n'
 
261
                             '1.1.1         barry@foo.com  20061213 | third\n'
 
262
                             '1.1.1.1.1     jerry@foo.com  20061213 | fourth\n'
 
263
                             '1.1.1.1.1.1.1 george@foo.com 20061213 | fifth\n'
 
264
                             '1.1.1.1.1.1.1 george@foo.com 20061213 | sixth\n',
346
265
                             sio.getvalue())
347
266
 
348
267
    def test_annotate_uses_branch_context(self):
351
270
        When annotating a non-mainline revision, the annotation should still
352
271
        use dotted revnos from the mainline.
353
272
        """
354
 
        builder = self.create_deeply_merged_trees()
 
273
        tree1 = self.create_deeply_merged_trees()
355
274
 
356
275
        sio = StringIO()
357
 
        annotate.annotate_file(builder.get_branch(), 'rev-1_3_1', 'a-id',
 
276
        annotate.annotate_file(tree1.branch, 'rev-1_1_1_1_1_1_1', 'a-id',
358
277
                               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',
 
278
        self.assertEqualDiff('1            joe@foo | first\n'
 
279
                             '1.1.1        barry@f | third\n'
 
280
                             '1.1.1.1.1    jerry@f | fourth\n'
 
281
                             '1.1.1.1.1.1> george@ | fifth\n'
 
282
                             '                     | sixth\n',
364
283
                             sio.getvalue())
365
284
 
366
285
    def test_annotate_show_ids(self):
367
 
        builder = self.create_deeply_merged_trees()
 
286
        tree1 = self.create_deeply_merged_trees()
368
287
 
369
288
        sio = StringIO()
370
 
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
289
        annotate.annotate_file(tree1.branch, 'rev-6', 'a-id',
371
290
                               to_file=sio, show_ids=True, full=False)
372
291
 
373
292
        # It looks better with real revision ids :)
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',
 
293
        self.assertEqualDiff('            rev-1 | first\n'
 
294
                             '            rev-2 | second\n'
 
295
                             '        rev-1_1_1 | third\n'
 
296
                             '    rev-1_1_1_1_1 | fourth\n'
 
297
                             'rev-1_1_1_1_1_1_1 | fifth\n'
 
298
                             '                  | sixth\n',
380
299
                             sio.getvalue())
381
300
 
382
301
        sio = StringIO()
383
 
        annotate.annotate_file(builder.get_branch(), 'rev-6', 'a-id',
 
302
        annotate.annotate_file(tree1.branch, 'rev-6', 'a-id',
384
303
                               to_file=sio, show_ids=True, full=True)
385
304
 
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',
 
305
        self.assertEqualDiff('            rev-1 | first\n'
 
306
                             '            rev-2 | second\n'
 
307
                             '        rev-1_1_1 | third\n'
 
308
                             '    rev-1_1_1_1_1 | fourth\n'
 
309
                             'rev-1_1_1_1_1_1_1 | fifth\n'
 
310
                             'rev-1_1_1_1_1_1_1 | sixth\n',
392
311
                             sio.getvalue())
393
312
 
394
313
    def test_annotate_unicode_author(self):
406
325
                     committer=u'p\xe9rez',
407
326
                     timestamp=1166046000.00, timezone=0)
408
327
 
409
 
        tree1.lock_read()
410
 
        self.addCleanup(tree1.unlock)
411
328
        # this passes if no exception is raised
412
329
        to_file = StringIO()
413
330
        annotate.annotate_file(tree1.branch, 'rev-1', 'a-id', to_file=to_file)
442
359
        tree1.add(['b'], ['b-id'])
443
360
        tree1.commit('b', rev_id='rev-2',
444
361
                     committer='Committer <committer@example.com>',
445
 
                     authors=['Author <author@example.com>'],
 
362
                     author='Author <author@example.com>',
446
363
                     timestamp=1166046000.00, timezone=0)
447
364
 
448
 
        tree1.lock_read()
449
 
        self.addCleanup(tree1.unlock)
450
365
        to_file = StringIO()
451
366
        annotate.annotate_file(tree1.branch, 'rev-1', 'a-id', to_file=to_file)
452
367
        self.assertEqual('1   committ | hello\n', to_file.getvalue())
469
384
    def test_reannotate(self):
470
385
        self.annotateEqual(parent_1, [parent_1], new_1, 'blahblah')
471
386
        self.annotateEqual(expected_2_1, [parent_2], new_1, 'blahblah')
472
 
        self.annotateEqual(expected_1_2_2, [parent_1, parent_2], new_2,
 
387
        self.annotateEqual(expected_1_2_2, [parent_1, parent_2], new_2, 
473
388
                           'blahblah')
474
389
 
475
390
    def test_reannotate_no_parents(self):