/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
4454.3.1 by John Arbash Meinel
Initial api for Annotator.
1
# Copyright (C) 2009 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 (
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
20
    _annotator_py,
4454.3.1 by John Arbash Meinel
Initial api for Annotator.
21
    errors,
4454.3.27 by John Arbash Meinel
Simplify the test__annotator tests by avoiding having a real repository.
22
    knit,
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
23
    revision,
4454.3.1 by John Arbash Meinel
Initial api for Annotator.
24
    tests,
25
    )
26
27
28
def load_tests(standard_tests, module, loader):
29
    """Parameterize tests for all versions of groupcompress."""
30
    scenarios = [
31
        ('python', {'module': _annotator_py}),
32
    ]
33
    suite = loader.suiteClass()
34
    if CompiledAnnotator.available():
35
        from bzrlib import _annotator_pyx
36
        scenarios.append(('C', {'module': _annotator_pyx}))
37
    else:
38
        # the compiled module isn't available, so we add a failing test
39
        class FailWithoutFeature(tests.TestCase):
40
            def test_fail(self):
41
                self.requireFeature(CompiledAnnotator)
42
        suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
43
    result = tests.multiply_tests(standard_tests, scenarios, suite)
44
    return result
45
46
47
class _CompiledAnnotator(tests.Feature):
48
49
    def _probe(self):
50
        try:
51
            import bzrlib._annotator_pyx
52
        except ImportError:
53
            return False
54
        return True
55
56
    def feature_name(self):
57
        return 'bzrlib._annotator_pyx'
58
59
CompiledAnnotator = _CompiledAnnotator()
60
61
62
class TestAnnotator(tests.TestCaseWithMemoryTransport):
63
64
    module = None # Set by load_tests
65
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
66
    fa_key = ('f-id', 'a-id')
67
    fb_key = ('f-id', 'b-id')
68
    fc_key = ('f-id', 'c-id')
69
    fd_key = ('f-id', 'd-id')
4454.3.12 by John Arbash Meinel
Finish fleshing out the ability to determine a revision after conflicts.
70
    fe_key = ('f-id', 'e-id')
71
    ff_key = ('f-id', 'f-id')
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
72
4454.3.2 by John Arbash Meinel
Start moving bits into helper functions. Add tests for multiple revs.
73
    def make_simple_text(self):
4454.3.27 by John Arbash Meinel
Simplify the test__annotator tests by avoiding having a real repository.
74
        # TODO: all we really need is a VersionedFile instance, we'd like to
75
        #       avoid creating all the intermediate stuff
76
        factory = knit.make_pack_factory(True, True, 2)
77
        self.vf = factory(self.get_transport())
4454.3.18 by John Arbash Meinel
Start tracking the number of children that need a given text.
78
        # This assumes nothing special happens during __init__, which may be
79
        # valid
80
        self.ann = self.module.Annotator(self.vf)
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
81
        #  A    'simple|content|'
82
        #  |
83
        #  B    'simple|new content|'
4454.3.27 by John Arbash Meinel
Simplify the test__annotator tests by avoiding having a real repository.
84
        self.vf.add_lines(self.fa_key, [], ['simple\n', 'content\n'])
85
        self.vf.add_lines(self.fb_key, [self.fa_key],
86
                          ['simple\n', 'new content\n'])
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
87
88
    def make_merge_text(self):
89
        self.make_simple_text()
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
90
        #  A    'simple|content|'
91
        #  |\
92
        #  B |  'simple|new content|'
93
        #  | |
94
        #  | C  'simple|from c|content|'
95
        #  |/
96
        #  D    'simple|from c|new content|introduced in merge|'
4454.3.27 by John Arbash Meinel
Simplify the test__annotator tests by avoiding having a real repository.
97
        self.vf.add_lines(self.fc_key, [self.fa_key],
98
                          ['simple\n', 'from c\n', 'content\n'])
99
        self.vf.add_lines(self.fd_key, [self.fb_key, self.fc_key],
100
                          ['simple\n', 'from c\n', 'new content\n',
101
                           'introduced in merge\n'])
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
102
103
    def make_common_merge_text(self):
104
        """Both sides of the merge will have introduced a line."""
105
        self.make_simple_text()
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
106
        #  A    'simple|content|'
107
        #  |\
108
        #  B |  'simple|new content|'
109
        #  | |
110
        #  | C  'simple|new content|'
111
        #  |/
112
        #  D    'simple|new content|'
4454.3.27 by John Arbash Meinel
Simplify the test__annotator tests by avoiding having a real repository.
113
        self.vf.add_lines(self.fc_key, [self.fa_key],
114
                          ['simple\n', 'new content\n'])
115
        self.vf.add_lines(self.fd_key, [self.fb_key, self.fc_key],
116
                          ['simple\n', 'new content\n'])
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
117
4454.3.12 by John Arbash Meinel
Finish fleshing out the ability to determine a revision after conflicts.
118
    def make_many_way_common_merge_text(self):
119
        self.make_simple_text()
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
120
        #  A-.    'simple|content|'
121
        #  |\ \
122
        #  B | |  'simple|new content|'
123
        #  | | |
124
        #  | C |  'simple|new content|'
125
        #  |/  |
126
        #  D   |  'simple|new content|'
127
        #  |   |
128
        #  |   E  'simple|new content|'
129
        #  |  /
130
        #  F-'    'simple|new content|'
4454.3.27 by John Arbash Meinel
Simplify the test__annotator tests by avoiding having a real repository.
131
        self.vf.add_lines(self.fc_key, [self.fa_key],
132
                          ['simple\n', 'new content\n'])
133
        self.vf.add_lines(self.fd_key, [self.fb_key, self.fc_key],
134
                          ['simple\n', 'new content\n'])
135
        self.vf.add_lines(self.fe_key, [self.fa_key],
136
                          ['simple\n', 'new content\n'])
137
        self.vf.add_lines(self.ff_key, [self.fd_key, self.fe_key],
138
                          ['simple\n', 'new content\n'])
4454.3.12 by John Arbash Meinel
Finish fleshing out the ability to determine a revision after conflicts.
139
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
140
    def make_merge_and_restored_text(self):
141
        self.make_simple_text()
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
142
        #  A    'simple|content|'
143
        #  |\
144
        #  B |  'simple|new content|'
145
        #  | |
146
        #  C |  'simple|content|' # reverted to A
147
        #   \|
148
        #    D  'simple|content|'
4454.3.27 by John Arbash Meinel
Simplify the test__annotator tests by avoiding having a real repository.
149
        # c reverts back to 'a' for the new content line
150
        self.vf.add_lines(self.fc_key, [self.fb_key],
151
                          ['simple\n', 'content\n'])
152
        # d merges 'a' and 'c', to find both claim last modified
153
        self.vf.add_lines(self.fd_key, [self.fa_key, self.fc_key],
154
                          ['simple\n', 'content\n'])
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
155
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
156
    def assertAnnotateEqual(self, expected_annotation, key, exp_text=None):
157
        annotation, lines = self.ann.annotate(key)
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
158
        self.assertEqual(expected_annotation, annotation)
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
159
        if exp_text is None:
160
            record = self.vf.get_record_stream([key], 'unordered', True).next()
161
            exp_text = record.get_bytes_as('fulltext')
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
162
        self.assertEqualDiff(exp_text, ''.join(lines))
4454.3.1 by John Arbash Meinel
Initial api for Annotator.
163
164
    def test_annotate_missing(self):
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
165
        self.make_simple_text()
4454.3.1 by John Arbash Meinel
Initial api for Annotator.
166
        self.assertRaises(errors.RevisionNotPresent,
4454.3.18 by John Arbash Meinel
Start tracking the number of children that need a given text.
167
                          self.ann.annotate, ('not', 'present'))
4454.3.1 by John Arbash Meinel
Initial api for Annotator.
168
169
    def test_annotate_simple(self):
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
170
        self.make_simple_text()
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
171
        self.assertAnnotateEqual([(self.fa_key,)]*2, self.fa_key)
172
        self.assertAnnotateEqual([(self.fa_key,), (self.fb_key,)], self.fb_key)
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
173
174
    def test_annotate_merge_text(self):
175
        self.make_merge_text()
176
        self.assertAnnotateEqual([(self.fa_key,), (self.fc_key,),
177
                                  (self.fb_key,), (self.fd_key,)],
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
178
                                 self.fd_key)
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
179
180
    def test_annotate_common_merge_text(self):
181
        self.make_common_merge_text()
182
        self.assertAnnotateEqual([(self.fa_key,), (self.fb_key, self.fc_key)],
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
183
                                 self.fd_key)
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
184
4454.3.12 by John Arbash Meinel
Finish fleshing out the ability to determine a revision after conflicts.
185
    def test_annotate_many_way_common_merge_text(self):
186
        self.make_many_way_common_merge_text()
187
        self.assertAnnotateEqual([(self.fa_key,),
188
                                  (self.fb_key, self.fc_key, self.fe_key)],
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
189
                                 self.ff_key)
4454.3.12 by John Arbash Meinel
Finish fleshing out the ability to determine a revision after conflicts.
190
4454.3.4 by John Arbash Meinel
New work on how to resolve conflict lines.
191
    def test_annotate_merge_and_restored(self):
192
        self.make_merge_and_restored_text()
193
        self.assertAnnotateEqual([(self.fa_key,), (self.fa_key, self.fc_key)],
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
194
                                 self.fd_key)
4454.3.10 by John Arbash Meinel
Start working on 'annotate_flat' which conforms to the original spec.
195
196
    def test_annotate_flat_simple(self):
197
        self.make_simple_text()
198
        self.assertEqual([(self.fa_key, 'simple\n'),
199
                          (self.fa_key, 'content\n'),
4454.3.18 by John Arbash Meinel
Start tracking the number of children that need a given text.
200
                         ], self.ann.annotate_flat(self.fa_key))
4454.3.10 by John Arbash Meinel
Start working on 'annotate_flat' which conforms to the original spec.
201
        self.assertEqual([(self.fa_key, 'simple\n'),
202
                          (self.fb_key, 'new content\n'),
4454.3.18 by John Arbash Meinel
Start tracking the number of children that need a given text.
203
                         ], self.ann.annotate_flat(self.fb_key))
4454.3.12 by John Arbash Meinel
Finish fleshing out the ability to determine a revision after conflicts.
204
205
    def test_annotate_flat_merge_and_restored_text(self):
206
        self.make_merge_and_restored_text()
207
        # fc is a simple dominator of fa
208
        self.assertEqual([(self.fa_key, 'simple\n'),
209
                          (self.fc_key, 'content\n'),
4454.3.18 by John Arbash Meinel
Start tracking the number of children that need a given text.
210
                         ], self.ann.annotate_flat(self.fd_key))
4454.3.12 by John Arbash Meinel
Finish fleshing out the ability to determine a revision after conflicts.
211
212
    def test_annotate_common_merge_text(self):
213
        self.make_common_merge_text()
214
        # there is no common point, so we just pick the lexicographical lowest
215
        # and 'b-id' comes before 'c-id'
216
        self.assertEqual([(self.fa_key, 'simple\n'),
217
                          (self.fb_key, 'new content\n'),
4454.3.18 by John Arbash Meinel
Start tracking the number of children that need a given text.
218
                         ], self.ann.annotate_flat(self.fd_key))
4454.3.12 by John Arbash Meinel
Finish fleshing out the ability to determine a revision after conflicts.
219
220
    def test_annotate_many_way_common_merge_text(self):
221
        self.make_many_way_common_merge_text()
4454.3.14 by John Arbash Meinel
Had a slightly bogus test.
222
        self.assertEqual([(self.fa_key, 'simple\n'),
223
                         (self.fb_key, 'new content\n')],
4454.3.18 by John Arbash Meinel
Start tracking the number of children that need a given text.
224
                         self.ann.annotate_flat(self.ff_key))
225
226
4454.3.19 by John Arbash Meinel
Have _record_annotation start to remove texts when they are no longer needed.
227
    def test_needed_keys_simple(self):
4454.3.18 by John Arbash Meinel
Start tracking the number of children that need a given text.
228
        self.make_simple_text()
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
229
        keys, ann_keys = self.ann._get_needed_keys(self.fb_key)
4454.3.18 by John Arbash Meinel
Start tracking the number of children that need a given text.
230
        self.assertEqual([self.fa_key, self.fb_key], sorted(keys))
231
        self.assertEqual({self.fa_key: 1, self.fb_key: 1},
232
                         self.ann._num_needed_children)
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
233
        self.assertEqual(set(), ann_keys)
4454.3.19 by John Arbash Meinel
Have _record_annotation start to remove texts when they are no longer needed.
234
235
    def test_needed_keys_many(self):
236
        self.make_many_way_common_merge_text()
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
237
        keys, ann_keys = self.ann._get_needed_keys(self.ff_key)
4454.3.19 by John Arbash Meinel
Have _record_annotation start to remove texts when they are no longer needed.
238
        self.assertEqual([self.fa_key, self.fb_key, self.fc_key,
239
                          self.fd_key, self.fe_key, self.ff_key,
240
                         ], sorted(keys))
241
        self.assertEqual({self.fa_key: 3,
242
                          self.fb_key: 1,
243
                          self.fc_key: 1,
244
                          self.fd_key: 1,
245
                          self.fe_key: 1,
246
                          self.ff_key: 1,
247
                         }, self.ann._num_needed_children)
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
248
        self.assertEqual(set(), ann_keys)
249
250
    def test_needed_keys_with_special_text(self):
251
        self.make_many_way_common_merge_text()
252
        spec_key = ('f-id', revision.CURRENT_REVISION)
253
        spec_text = 'simple\nnew content\nlocally modified\n'
254
        self.ann.add_special_text(spec_key, [self.fd_key, self.fe_key],
255
                                  spec_text)
256
        keys, ann_keys = self.ann._get_needed_keys(spec_key)
257
        self.assertEqual([self.fa_key, self.fb_key, self.fc_key,
258
                          self.fd_key, self.fe_key,
259
                         ], sorted(keys))
260
        self.assertEqual([spec_key], sorted(ann_keys))
4454.3.19 by John Arbash Meinel
Have _record_annotation start to remove texts when they are no longer needed.
261
4454.3.62 by John Arbash Meinel
Add a test that shows when parent texts, etc, are present, we don't request again.
262
    def test_needed_keys_with_parent_texts(self):
263
        self.make_many_way_common_merge_text()
264
        # If 'D' and 'E' are already annotated, we don't need to extract all
265
        # the texts
266
        #  D   |  'simple|new content|'
267
        #  |   |
268
        #  |   E  'simple|new content|'
269
        #  |  /
270
        #  F-'    'simple|new content|'
271
        self.ann._parent_map[self.fd_key] = (self.fb_key, self.fc_key)
272
        self.ann._text_cache[self.fd_key] = ['simple\n', 'new content\n']
273
        self.ann._annotations_cache[self.fd_key] = [
274
            (self.fa_key,),
275
            (self.fb_key, self.fc_key),
276
            ]
277
        self.ann._parent_map[self.fe_key] = (self.fa_key,)
278
        self.ann._text_cache[self.fe_key] = ['simple\n', 'new content\n']
279
        self.ann._annotations_cache[self.fe_key] = [
280
            (self.fa_key,),
281
            (self.fe_key,),
282
            ]
283
        keys, ann_keys = self.ann._get_needed_keys(self.ff_key)
284
        self.assertEqual([self.ff_key], sorted(keys))
285
        self.assertEqual({self.fd_key: 1,
286
                          self.fe_key: 1,
287
                          self.ff_key: 1,
288
                         }, self.ann._num_needed_children)
289
        self.assertEqual([], sorted(ann_keys))
290
4454.3.19 by John Arbash Meinel
Have _record_annotation start to remove texts when they are no longer needed.
291
    def test_record_annotation_removes_texts(self):
292
        self.make_many_way_common_merge_text()
293
        # Populate the caches
294
        for x in self.ann._get_needed_texts(self.ff_key):
295
            continue
296
        self.assertEqual({self.fa_key: 3,
297
                          self.fb_key: 1,
298
                          self.fc_key: 1,
299
                          self.fd_key: 1,
300
                          self.fe_key: 1,
301
                          self.ff_key: 1,
302
                         }, self.ann._num_needed_children)
303
        self.assertEqual([self.fa_key, self.fb_key, self.fc_key,
304
                          self.fd_key, self.fe_key, self.ff_key,
305
                         ], sorted(self.ann._text_cache.keys()))
4454.3.22 by John Arbash Meinel
Need to record the other annotations before we can record this,
306
        self.ann._record_annotation(self.fa_key, [], [])
4454.3.19 by John Arbash Meinel
Have _record_annotation start to remove texts when they are no longer needed.
307
        self.ann._record_annotation(self.fb_key, [self.fa_key], [])
308
        self.assertEqual({self.fa_key: 2,
309
                          self.fb_key: 1,
310
                          self.fc_key: 1,
311
                          self.fd_key: 1,
312
                          self.fe_key: 1,
313
                          self.ff_key: 1,
314
                         }, self.ann._num_needed_children)
315
        self.assertTrue(self.fa_key in self.ann._text_cache)
4454.3.21 by John Arbash Meinel
Assert that entries in the annotation cache also get cleaned up.
316
        self.assertTrue(self.fa_key in self.ann._annotations_cache)
4454.3.22 by John Arbash Meinel
Need to record the other annotations before we can record this,
317
        self.ann._record_annotation(self.fc_key, [self.fa_key], [])
4454.3.19 by John Arbash Meinel
Have _record_annotation start to remove texts when they are no longer needed.
318
        self.ann._record_annotation(self.fd_key, [self.fb_key, self.fc_key], [])
4454.3.22 by John Arbash Meinel
Need to record the other annotations before we can record this,
319
        self.assertEqual({self.fa_key: 1,
4454.3.19 by John Arbash Meinel
Have _record_annotation start to remove texts when they are no longer needed.
320
                          self.fb_key: 0,
321
                          self.fc_key: 0,
322
                          self.fd_key: 1,
323
                          self.fe_key: 1,
324
                          self.ff_key: 1,
325
                         }, self.ann._num_needed_children)
326
        self.assertTrue(self.fa_key in self.ann._text_cache)
4454.3.21 by John Arbash Meinel
Assert that entries in the annotation cache also get cleaned up.
327
        self.assertTrue(self.fa_key in self.ann._annotations_cache)
4454.3.19 by John Arbash Meinel
Have _record_annotation start to remove texts when they are no longer needed.
328
        self.assertFalse(self.fb_key in self.ann._text_cache)
4454.3.22 by John Arbash Meinel
Need to record the other annotations before we can record this,
329
        self.assertFalse(self.fb_key in self.ann._annotations_cache)
4454.3.19 by John Arbash Meinel
Have _record_annotation start to remove texts when they are no longer needed.
330
        self.assertFalse(self.fc_key in self.ann._text_cache)
4454.3.22 by John Arbash Meinel
Need to record the other annotations before we can record this,
331
        self.assertFalse(self.fc_key in self.ann._annotations_cache)
4454.3.61 by John Arbash Meinel
Start implementing an Annotator.add_special_text functionality.
332
333
    def test_annotate_special_text(self):
334
        # Things like WT and PreviewTree want to annotate an arbitrary text
335
        # ('current:') so we need a way to add that to the group of files to be
336
        # annotated.
337
        self.make_many_way_common_merge_text()
338
        #  A-.    'simple|content|'
339
        #  |\ \
340
        #  B | |  'simple|new content|'
341
        #  | | |
342
        #  | C |  'simple|new content|'
343
        #  |/  |
344
        #  D   |  'simple|new content|'
345
        #  |   |
346
        #  |   E  'simple|new content|'
347
        #  |  /
348
        #  SPEC   'simple|new content|locally modified|'
349
        spec_key = ('f-id', revision.CURRENT_REVISION)
350
        spec_text = 'simple\nnew content\nlocally modified\n'
351
        self.ann.add_special_text(spec_key, [self.fd_key, self.fe_key],
352
                                  spec_text)
353
        self.assertAnnotateEqual([(self.fa_key,),
354
                                  (self.fb_key, self.fc_key, self.fe_key),
355
                                  (spec_key,)
356
                                 ], spec_key,
357
                                 exp_text=spec_text)