/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__annotator.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:
1
 
# Copyright (C) 2009, 2010 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
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
16
 
 
17
 
"""Tests for Annotators."""
18
 
 
19
 
from bzrlib import (
20
 
    annotate,
21
 
    _annotator_py,
22
 
    errors,
23
 
    knit,
24
 
    revision,
25
 
    tests,
26
 
    )
27
 
 
28
 
 
29
 
def load_tests(standard_tests, module, loader):
30
 
    """Parameterize tests for all versions of groupcompress."""
31
 
    suite, _ = tests.permute_tests_for_extension(standard_tests, loader,
32
 
        'bzrlib._annotator_py', 'bzrlib._annotator_pyx')
33
 
    return suite
34
 
 
35
 
 
36
 
class TestAnnotator(tests.TestCaseWithMemoryTransport):
37
 
 
38
 
    module = None # Set by load_tests
39
 
 
40
 
    fa_key = ('f-id', 'a-id')
41
 
    fb_key = ('f-id', 'b-id')
42
 
    fc_key = ('f-id', 'c-id')
43
 
    fd_key = ('f-id', 'd-id')
44
 
    fe_key = ('f-id', 'e-id')
45
 
    ff_key = ('f-id', 'f-id')
46
 
 
47
 
    def make_no_graph_texts(self):
48
 
        factory = knit.make_pack_factory(False, False, 2)
49
 
        self.vf = factory(self.get_transport())
50
 
        self.ann = self.module.Annotator(self.vf)
51
 
        self.vf.add_lines(self.fa_key, (), ['simple\n', 'content\n'])
52
 
        self.vf.add_lines(self.fb_key, (), ['simple\n', 'new content\n'])
53
 
 
54
 
    def make_simple_text(self):
55
 
        # TODO: all we really need is a VersionedFile instance, we'd like to
56
 
        #       avoid creating all the intermediate stuff
57
 
        factory = knit.make_pack_factory(True, True, 2)
58
 
        self.vf = factory(self.get_transport())
59
 
        # This assumes nothing special happens during __init__, which may be
60
 
        # valid
61
 
        self.ann = self.module.Annotator(self.vf)
62
 
        #  A    'simple|content|'
63
 
        #  |
64
 
        #  B    'simple|new content|'
65
 
        self.vf.add_lines(self.fa_key, [], ['simple\n', 'content\n'])
66
 
        self.vf.add_lines(self.fb_key, [self.fa_key],
67
 
                          ['simple\n', 'new content\n'])
68
 
 
69
 
    def make_merge_text(self):
70
 
        self.make_simple_text()
71
 
        #  A    'simple|content|'
72
 
        #  |\
73
 
        #  B |  'simple|new content|'
74
 
        #  | |
75
 
        #  | C  'simple|from c|content|'
76
 
        #  |/
77
 
        #  D    'simple|from c|new content|introduced in merge|'
78
 
        self.vf.add_lines(self.fc_key, [self.fa_key],
79
 
                          ['simple\n', 'from c\n', 'content\n'])
80
 
        self.vf.add_lines(self.fd_key, [self.fb_key, self.fc_key],
81
 
                          ['simple\n', 'from c\n', 'new content\n',
82
 
                           'introduced in merge\n'])
83
 
 
84
 
    def make_common_merge_text(self):
85
 
        """Both sides of the merge will have introduced a line."""
86
 
        self.make_simple_text()
87
 
        #  A    'simple|content|'
88
 
        #  |\
89
 
        #  B |  'simple|new content|'
90
 
        #  | |
91
 
        #  | C  'simple|new content|'
92
 
        #  |/
93
 
        #  D    'simple|new content|'
94
 
        self.vf.add_lines(self.fc_key, [self.fa_key],
95
 
                          ['simple\n', 'new content\n'])
96
 
        self.vf.add_lines(self.fd_key, [self.fb_key, self.fc_key],
97
 
                          ['simple\n', 'new content\n'])
98
 
 
99
 
    def make_many_way_common_merge_text(self):
100
 
        self.make_simple_text()
101
 
        #  A-.    'simple|content|'
102
 
        #  |\ \
103
 
        #  B | |  'simple|new content|'
104
 
        #  | | |
105
 
        #  | C |  'simple|new content|'
106
 
        #  |/  |
107
 
        #  D   |  'simple|new content|'
108
 
        #  |   |
109
 
        #  |   E  'simple|new content|'
110
 
        #  |  /
111
 
        #  F-'    'simple|new content|'
112
 
        self.vf.add_lines(self.fc_key, [self.fa_key],
113
 
                          ['simple\n', 'new content\n'])
114
 
        self.vf.add_lines(self.fd_key, [self.fb_key, self.fc_key],
115
 
                          ['simple\n', 'new content\n'])
116
 
        self.vf.add_lines(self.fe_key, [self.fa_key],
117
 
                          ['simple\n', 'new content\n'])
118
 
        self.vf.add_lines(self.ff_key, [self.fd_key, self.fe_key],
119
 
                          ['simple\n', 'new content\n'])
120
 
 
121
 
    def make_merge_and_restored_text(self):
122
 
        self.make_simple_text()
123
 
        #  A    'simple|content|'
124
 
        #  |\
125
 
        #  B |  'simple|new content|'
126
 
        #  | |
127
 
        #  C |  'simple|content|' # reverted to A
128
 
        #   \|
129
 
        #    D  'simple|content|'
130
 
        # c reverts back to 'a' for the new content line
131
 
        self.vf.add_lines(self.fc_key, [self.fb_key],
132
 
                          ['simple\n', 'content\n'])
133
 
        # d merges 'a' and 'c', to find both claim last modified
134
 
        self.vf.add_lines(self.fd_key, [self.fa_key, self.fc_key],
135
 
                          ['simple\n', 'content\n'])
136
 
 
137
 
    def assertAnnotateEqual(self, expected_annotation, key, exp_text=None):
138
 
        annotation, lines = self.ann.annotate(key)
139
 
        self.assertEqual(expected_annotation, annotation)
140
 
        if exp_text is None:
141
 
            record = self.vf.get_record_stream([key], 'unordered', True).next()
142
 
            exp_text = record.get_bytes_as('fulltext')
143
 
        self.assertEqualDiff(exp_text, ''.join(lines))
144
 
 
145
 
    def test_annotate_missing(self):
146
 
        self.make_simple_text()
147
 
        self.assertRaises(errors.RevisionNotPresent,
148
 
                          self.ann.annotate, ('not', 'present'))
149
 
 
150
 
    def test_annotate_simple(self):
151
 
        self.make_simple_text()
152
 
        self.assertAnnotateEqual([(self.fa_key,)]*2, self.fa_key)
153
 
        self.assertAnnotateEqual([(self.fa_key,), (self.fb_key,)], self.fb_key)
154
 
 
155
 
    def test_annotate_merge_text(self):
156
 
        self.make_merge_text()
157
 
        self.assertAnnotateEqual([(self.fa_key,), (self.fc_key,),
158
 
                                  (self.fb_key,), (self.fd_key,)],
159
 
                                 self.fd_key)
160
 
 
161
 
    def test_annotate_common_merge_text(self):
162
 
        self.make_common_merge_text()
163
 
        self.assertAnnotateEqual([(self.fa_key,), (self.fb_key, self.fc_key)],
164
 
                                 self.fd_key)
165
 
 
166
 
    def test_annotate_many_way_common_merge_text(self):
167
 
        self.make_many_way_common_merge_text()
168
 
        self.assertAnnotateEqual([(self.fa_key,),
169
 
                                  (self.fb_key, self.fc_key, self.fe_key)],
170
 
                                 self.ff_key)
171
 
 
172
 
    def test_annotate_merge_and_restored(self):
173
 
        self.make_merge_and_restored_text()
174
 
        self.assertAnnotateEqual([(self.fa_key,), (self.fa_key, self.fc_key)],
175
 
                                 self.fd_key)
176
 
 
177
 
    def test_annotate_flat_simple(self):
178
 
        self.make_simple_text()
179
 
        self.assertEqual([(self.fa_key, 'simple\n'),
180
 
                          (self.fa_key, 'content\n'),
181
 
                         ], self.ann.annotate_flat(self.fa_key))
182
 
        self.assertEqual([(self.fa_key, 'simple\n'),
183
 
                          (self.fb_key, 'new content\n'),
184
 
                         ], self.ann.annotate_flat(self.fb_key))
185
 
 
186
 
    def test_annotate_flat_merge_and_restored_text(self):
187
 
        self.make_merge_and_restored_text()
188
 
        # fc is a simple dominator of fa
189
 
        self.assertEqual([(self.fa_key, 'simple\n'),
190
 
                          (self.fc_key, 'content\n'),
191
 
                         ], self.ann.annotate_flat(self.fd_key))
192
 
 
193
 
    def test_annotate_common_merge_text(self):
194
 
        self.make_common_merge_text()
195
 
        # there is no common point, so we just pick the lexicographical lowest
196
 
        # and 'b-id' comes before 'c-id'
197
 
        self.assertEqual([(self.fa_key, 'simple\n'),
198
 
                          (self.fb_key, 'new content\n'),
199
 
                         ], self.ann.annotate_flat(self.fd_key))
200
 
 
201
 
    def test_annotate_many_way_common_merge_text(self):
202
 
        self.make_many_way_common_merge_text()
203
 
        self.assertEqual([(self.fa_key, 'simple\n'),
204
 
                         (self.fb_key, 'new content\n')],
205
 
                         self.ann.annotate_flat(self.ff_key))
206
 
 
207
 
    def test_annotate_flat_respects_break_ann_tie(self):
208
 
        tiebreaker = annotate._break_annotation_tie
209
 
        try:
210
 
            calls = []
211
 
            def custom_tiebreaker(annotated_lines):
212
 
                self.assertEqual(2, len(annotated_lines))
213
 
                left = annotated_lines[0]
214
 
                self.assertEqual(2, len(left))
215
 
                self.assertEqual('new content\n', left[1])
216
 
                right = annotated_lines[1]
217
 
                self.assertEqual(2, len(right))
218
 
                self.assertEqual('new content\n', right[1])
219
 
                calls.append((left[0], right[0]))
220
 
                # Our custom tiebreaker takes the *largest* value, rather than
221
 
                # the *smallest* value
222
 
                if left[0] < right[0]:
223
 
                    return right
224
 
                else:
225
 
                    return left
226
 
            annotate._break_annotation_tie = custom_tiebreaker
227
 
            self.make_many_way_common_merge_text()
228
 
            self.assertEqual([(self.fa_key, 'simple\n'),
229
 
                             (self.fe_key, 'new content\n')],
230
 
                             self.ann.annotate_flat(self.ff_key))
231
 
            self.assertEqual([(self.fe_key, self.fc_key),
232
 
                              (self.fe_key, self.fb_key)], calls)
233
 
        finally:
234
 
            annotate._break_annotation_tie = tiebreaker
235
 
 
236
 
 
237
 
    def test_needed_keys_simple(self):
238
 
        self.make_simple_text()
239
 
        keys, ann_keys = self.ann._get_needed_keys(self.fb_key)
240
 
        self.assertEqual([self.fa_key, self.fb_key], sorted(keys))
241
 
        self.assertEqual({self.fa_key: 1, self.fb_key: 1},
242
 
                         self.ann._num_needed_children)
243
 
        self.assertEqual(set(), ann_keys)
244
 
 
245
 
    def test_needed_keys_many(self):
246
 
        self.make_many_way_common_merge_text()
247
 
        keys, ann_keys = self.ann._get_needed_keys(self.ff_key)
248
 
        self.assertEqual([self.fa_key, self.fb_key, self.fc_key,
249
 
                          self.fd_key, self.fe_key, self.ff_key,
250
 
                         ], sorted(keys))
251
 
        self.assertEqual({self.fa_key: 3,
252
 
                          self.fb_key: 1,
253
 
                          self.fc_key: 1,
254
 
                          self.fd_key: 1,
255
 
                          self.fe_key: 1,
256
 
                          self.ff_key: 1,
257
 
                         }, self.ann._num_needed_children)
258
 
        self.assertEqual(set(), ann_keys)
259
 
 
260
 
    def test_needed_keys_with_special_text(self):
261
 
        self.make_many_way_common_merge_text()
262
 
        spec_key = ('f-id', revision.CURRENT_REVISION)
263
 
        spec_text = 'simple\nnew content\nlocally modified\n'
264
 
        self.ann.add_special_text(spec_key, [self.fd_key, self.fe_key],
265
 
                                  spec_text)
266
 
        keys, ann_keys = self.ann._get_needed_keys(spec_key)
267
 
        self.assertEqual([self.fa_key, self.fb_key, self.fc_key,
268
 
                          self.fd_key, self.fe_key,
269
 
                         ], sorted(keys))
270
 
        self.assertEqual([spec_key], sorted(ann_keys))
271
 
 
272
 
    def test_needed_keys_with_parent_texts(self):
273
 
        self.make_many_way_common_merge_text()
274
 
        # If 'D' and 'E' are already annotated, we don't need to extract all
275
 
        # the texts
276
 
        #  D   |  'simple|new content|'
277
 
        #  |   |
278
 
        #  |   E  'simple|new content|'
279
 
        #  |  /
280
 
        #  F-'    'simple|new content|'
281
 
        self.ann._parent_map[self.fd_key] = (self.fb_key, self.fc_key)
282
 
        self.ann._text_cache[self.fd_key] = ['simple\n', 'new content\n']
283
 
        self.ann._annotations_cache[self.fd_key] = [
284
 
            (self.fa_key,),
285
 
            (self.fb_key, self.fc_key),
286
 
            ]
287
 
        self.ann._parent_map[self.fe_key] = (self.fa_key,)
288
 
        self.ann._text_cache[self.fe_key] = ['simple\n', 'new content\n']
289
 
        self.ann._annotations_cache[self.fe_key] = [
290
 
            (self.fa_key,),
291
 
            (self.fe_key,),
292
 
            ]
293
 
        keys, ann_keys = self.ann._get_needed_keys(self.ff_key)
294
 
        self.assertEqual([self.ff_key], sorted(keys))
295
 
        self.assertEqual({self.fd_key: 1,
296
 
                          self.fe_key: 1,
297
 
                          self.ff_key: 1,
298
 
                         }, self.ann._num_needed_children)
299
 
        self.assertEqual([], sorted(ann_keys))
300
 
 
301
 
    def test_record_annotation_removes_texts(self):
302
 
        self.make_many_way_common_merge_text()
303
 
        # Populate the caches
304
 
        for x in self.ann._get_needed_texts(self.ff_key):
305
 
            continue
306
 
        self.assertEqual({self.fa_key: 3,
307
 
                          self.fb_key: 1,
308
 
                          self.fc_key: 1,
309
 
                          self.fd_key: 1,
310
 
                          self.fe_key: 1,
311
 
                          self.ff_key: 1,
312
 
                         }, self.ann._num_needed_children)
313
 
        self.assertEqual([self.fa_key, self.fb_key, self.fc_key,
314
 
                          self.fd_key, self.fe_key, self.ff_key,
315
 
                         ], sorted(self.ann._text_cache.keys()))
316
 
        self.ann._record_annotation(self.fa_key, [], [])
317
 
        self.ann._record_annotation(self.fb_key, [self.fa_key], [])
318
 
        self.assertEqual({self.fa_key: 2,
319
 
                          self.fb_key: 1,
320
 
                          self.fc_key: 1,
321
 
                          self.fd_key: 1,
322
 
                          self.fe_key: 1,
323
 
                          self.ff_key: 1,
324
 
                         }, self.ann._num_needed_children)
325
 
        self.assertTrue(self.fa_key in self.ann._text_cache)
326
 
        self.assertTrue(self.fa_key in self.ann._annotations_cache)
327
 
        self.ann._record_annotation(self.fc_key, [self.fa_key], [])
328
 
        self.ann._record_annotation(self.fd_key, [self.fb_key, self.fc_key], [])
329
 
        self.assertEqual({self.fa_key: 1,
330
 
                          self.fb_key: 0,
331
 
                          self.fc_key: 0,
332
 
                          self.fd_key: 1,
333
 
                          self.fe_key: 1,
334
 
                          self.ff_key: 1,
335
 
                         }, self.ann._num_needed_children)
336
 
        self.assertTrue(self.fa_key in self.ann._text_cache)
337
 
        self.assertTrue(self.fa_key in self.ann._annotations_cache)
338
 
        self.assertFalse(self.fb_key in self.ann._text_cache)
339
 
        self.assertFalse(self.fb_key in self.ann._annotations_cache)
340
 
        self.assertFalse(self.fc_key in self.ann._text_cache)
341
 
        self.assertFalse(self.fc_key in self.ann._annotations_cache)
342
 
 
343
 
    def test_annotate_special_text(self):
344
 
        # Things like WT and PreviewTree want to annotate an arbitrary text
345
 
        # ('current:') so we need a way to add that to the group of files to be
346
 
        # annotated.
347
 
        self.make_many_way_common_merge_text()
348
 
        #  A-.    'simple|content|'
349
 
        #  |\ \
350
 
        #  B | |  'simple|new content|'
351
 
        #  | | |
352
 
        #  | C |  'simple|new content|'
353
 
        #  |/  |
354
 
        #  D   |  'simple|new content|'
355
 
        #  |   |
356
 
        #  |   E  'simple|new content|'
357
 
        #  |  /
358
 
        #  SPEC   'simple|new content|locally modified|'
359
 
        spec_key = ('f-id', revision.CURRENT_REVISION)
360
 
        spec_text = 'simple\nnew content\nlocally modified\n'
361
 
        self.ann.add_special_text(spec_key, [self.fd_key, self.fe_key],
362
 
                                  spec_text)
363
 
        self.assertAnnotateEqual([(self.fa_key,),
364
 
                                  (self.fb_key, self.fc_key, self.fe_key),
365
 
                                  (spec_key,),
366
 
                                 ], spec_key,
367
 
                                 exp_text=spec_text)
368
 
 
369
 
    def test_no_graph(self):
370
 
        self.make_no_graph_texts()
371
 
        self.assertAnnotateEqual([(self.fa_key,),
372
 
                                  (self.fa_key,),
373
 
                                 ], self.fa_key)
374
 
        self.assertAnnotateEqual([(self.fb_key,),
375
 
                                  (self.fb_key,),
376
 
                                 ], self.fb_key)