/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_index.py

  • Committer: Robert Collins
  • Date: 2007-09-19 05:14:14 UTC
  • mto: (2835.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 2836.
  • Revision ID: robertc@robertcollins.net-20070919051414-2tgjqteg7k3ps4h0
* ``pull``, ``merge`` and ``push`` will no longer silently correct some
  repository index errors that occured as a result of the Weave disk format.
  Instead the ``reconcile`` command needs to be run to correct those
  problems if they exist (and it has been able to fix most such problems
  since bzr 0.8). Some new problems have been identified during this release
  and you should run ``bzr check`` once on every repository to see if you
  need to reconcile. If you cannot ``pull`` or ``merge`` from a remote
  repository due to mismatched parent errors - a symptom of index errors -
  you should simply take a full copy of that remote repository to a clean
  directory outside any local repositories, then run reconcile on it, and
  finally pull from it locally. (And naturally email the repositories owner
  to ask them to upgrade and run reconcile).
  (Robert Collins)

* ``VersionedFile.fix_parents`` has been removed as a harmful API.
  ``VersionedFile.join`` will no longer accept different parents on either
  side of a join - it will either ignore them, or error, depending on the
  implementation. See notes when upgrading for more information.
  (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2007 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""Tests for indices."""
 
18
 
 
19
from bzrlib import errors
 
20
from bzrlib.index import *
 
21
from bzrlib.tests import TestCaseWithMemoryTransport
 
22
 
 
23
 
 
24
class TestGraphIndexBuilder(TestCaseWithMemoryTransport):
 
25
 
 
26
    def test_build_index_empty(self):
 
27
        builder = GraphIndexBuilder()
 
28
        stream = builder.finish()
 
29
        contents = stream.read()
 
30
        self.assertEqual(
 
31
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\nlen=0\n\n",
 
32
            contents)
 
33
 
 
34
    def test_build_index_empty_two_element_keys(self):
 
35
        builder = GraphIndexBuilder(key_elements=2)
 
36
        stream = builder.finish()
 
37
        contents = stream.read()
 
38
        self.assertEqual(
 
39
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=2\nlen=0\n\n",
 
40
            contents)
 
41
 
 
42
    def test_build_index_one_reference_list_empty(self):
 
43
        builder = GraphIndexBuilder(reference_lists=1)
 
44
        stream = builder.finish()
 
45
        contents = stream.read()
 
46
        self.assertEqual(
 
47
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=0\n\n",
 
48
            contents)
 
49
 
 
50
    def test_build_index_two_reference_list_empty(self):
 
51
        builder = GraphIndexBuilder(reference_lists=2)
 
52
        stream = builder.finish()
 
53
        contents = stream.read()
 
54
        self.assertEqual(
 
55
            "Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\nlen=0\n\n",
 
56
            contents)
 
57
 
 
58
    def test_build_index_one_node_no_refs(self):
 
59
        builder = GraphIndexBuilder()
 
60
        builder.add_node(('akey', ), 'data')
 
61
        stream = builder.finish()
 
62
        contents = stream.read()
 
63
        self.assertEqual(
 
64
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\nlen=1\n"
 
65
            "akey\x00\x00\x00data\n\n", contents)
 
66
 
 
67
    def test_build_index_one_node_no_refs_accepts_empty_reflist(self):
 
68
        builder = GraphIndexBuilder()
 
69
        builder.add_node(('akey', ), 'data', ())
 
70
        stream = builder.finish()
 
71
        contents = stream.read()
 
72
        self.assertEqual(
 
73
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\nlen=1\n"
 
74
            "akey\x00\x00\x00data\n\n", contents)
 
75
 
 
76
    def test_build_index_one_node_2_element_keys(self):
 
77
        # multipart keys are separated by \x00 - because they are fixed length,
 
78
        # not variable this does not cause any issues, and seems clearer to the
 
79
        # author.
 
80
        builder = GraphIndexBuilder(key_elements=2)
 
81
        builder.add_node(('akey', 'secondpart'), 'data')
 
82
        stream = builder.finish()
 
83
        contents = stream.read()
 
84
        self.assertEqual(
 
85
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=2\nlen=1\n"
 
86
            "akey\x00secondpart\x00\x00\x00data\n\n", contents)
 
87
 
 
88
    def test_add_node_empty_value(self):
 
89
        builder = GraphIndexBuilder()
 
90
        builder.add_node(('akey', ), '')
 
91
        stream = builder.finish()
 
92
        contents = stream.read()
 
93
        self.assertEqual(
 
94
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\nlen=1\n"
 
95
            "akey\x00\x00\x00\n\n", contents)
 
96
 
 
97
    def test_build_index_nodes_sorted(self):
 
98
        # the highest sorted node comes first.
 
99
        builder = GraphIndexBuilder()
 
100
        # use three to have a good chance of glitching dictionary hash
 
101
        # lookups etc. Insert in randomish order that is not correct
 
102
        # and not the reverse of the correct order.
 
103
        builder.add_node(('2002', ), 'data')
 
104
        builder.add_node(('2000', ), 'data')
 
105
        builder.add_node(('2001', ), 'data')
 
106
        stream = builder.finish()
 
107
        contents = stream.read()
 
108
        self.assertEqual(
 
109
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\nlen=3\n"
 
110
            "2000\x00\x00\x00data\n"
 
111
            "2001\x00\x00\x00data\n"
 
112
            "2002\x00\x00\x00data\n"
 
113
            "\n", contents)
 
114
 
 
115
    def test_build_index_2_element_key_nodes_sorted(self):
 
116
        # multiple element keys are sorted first-key, second-key.
 
117
        builder = GraphIndexBuilder(key_elements=2)
 
118
        # use three values of each key element, to have a good chance of
 
119
        # glitching dictionary hash lookups etc. Insert in randomish order that
 
120
        # is not correct and not the reverse of the correct order.
 
121
        builder.add_node(('2002', '2002'), 'data')
 
122
        builder.add_node(('2002', '2000'), 'data')
 
123
        builder.add_node(('2002', '2001'), 'data')
 
124
        builder.add_node(('2000', '2002'), 'data')
 
125
        builder.add_node(('2000', '2000'), 'data')
 
126
        builder.add_node(('2000', '2001'), 'data')
 
127
        builder.add_node(('2001', '2002'), 'data')
 
128
        builder.add_node(('2001', '2000'), 'data')
 
129
        builder.add_node(('2001', '2001'), 'data')
 
130
        stream = builder.finish()
 
131
        contents = stream.read()
 
132
        self.assertEqual(
 
133
            "Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=2\nlen=9\n"
 
134
            "2000\x002000\x00\x00\x00data\n"
 
135
            "2000\x002001\x00\x00\x00data\n"
 
136
            "2000\x002002\x00\x00\x00data\n"
 
137
            "2001\x002000\x00\x00\x00data\n"
 
138
            "2001\x002001\x00\x00\x00data\n"
 
139
            "2001\x002002\x00\x00\x00data\n"
 
140
            "2002\x002000\x00\x00\x00data\n"
 
141
            "2002\x002001\x00\x00\x00data\n"
 
142
            "2002\x002002\x00\x00\x00data\n"
 
143
            "\n", contents)
 
144
 
 
145
    def test_build_index_reference_lists_are_included_one(self):
 
146
        builder = GraphIndexBuilder(reference_lists=1)
 
147
        builder.add_node(('key', ), 'data', ([], ))
 
148
        stream = builder.finish()
 
149
        contents = stream.read()
 
150
        self.assertEqual(
 
151
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=1\n"
 
152
            "key\x00\x00\x00data\n"
 
153
            "\n", contents)
 
154
 
 
155
    def test_build_index_reference_lists_with_2_element_keys(self):
 
156
        builder = GraphIndexBuilder(reference_lists=1, key_elements=2)
 
157
        builder.add_node(('key', 'key2'), 'data', ([], ))
 
158
        stream = builder.finish()
 
159
        contents = stream.read()
 
160
        self.assertEqual(
 
161
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=2\nlen=1\n"
 
162
            "key\x00key2\x00\x00\x00data\n"
 
163
            "\n", contents)
 
164
 
 
165
    def test_build_index_reference_lists_are_included_two(self):
 
166
        builder = GraphIndexBuilder(reference_lists=2)
 
167
        builder.add_node(('key', ), 'data', ([], []))
 
168
        stream = builder.finish()
 
169
        contents = stream.read()
 
170
        self.assertEqual(
 
171
            "Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\nlen=1\n"
 
172
            "key\x00\x00\t\x00data\n"
 
173
            "\n", contents)
 
174
 
 
175
    def test_node_references_are_byte_offsets(self):
 
176
        builder = GraphIndexBuilder(reference_lists=1)
 
177
        builder.add_node(('reference', ), 'data', ([], ))
 
178
        builder.add_node(('key', ), 'data', ([('reference', )], ))
 
179
        stream = builder.finish()
 
180
        contents = stream.read()
 
181
        self.assertEqual(
 
182
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=2\n"
 
183
            "key\x00\x0072\x00data\n"
 
184
            "reference\x00\x00\x00data\n"
 
185
            "\n", contents)
 
186
 
 
187
    def test_node_references_are_cr_delimited(self):
 
188
        builder = GraphIndexBuilder(reference_lists=1)
 
189
        builder.add_node(('reference', ), 'data', ([], ))
 
190
        builder.add_node(('reference2', ), 'data', ([], ))
 
191
        builder.add_node(('key', ), 'data', ([('reference', ), ('reference2', )], ))
 
192
        stream = builder.finish()
 
193
        contents = stream.read()
 
194
        self.assertEqual(
 
195
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=3\n"
 
196
            "key\x00\x00077\r094\x00data\n"
 
197
            "reference\x00\x00\x00data\n"
 
198
            "reference2\x00\x00\x00data\n"
 
199
            "\n", contents)
 
200
 
 
201
    def test_multiple_reference_lists_are_tab_delimited(self):
 
202
        builder = GraphIndexBuilder(reference_lists=2)
 
203
        builder.add_node(('keference', ), 'data', ([], []))
 
204
        builder.add_node(('rey', ), 'data', ([('keference', )], [('keference', )]))
 
205
        stream = builder.finish()
 
206
        contents = stream.read()
 
207
        self.assertEqual(
 
208
            "Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\nlen=2\n"
 
209
            "keference\x00\x00\t\x00data\n"
 
210
            "rey\x00\x0059\t59\x00data\n"
 
211
            "\n", contents)
 
212
 
 
213
    def test_add_node_referencing_missing_key_makes_absent(self):
 
214
        builder = GraphIndexBuilder(reference_lists=1)
 
215
        builder.add_node(('rey', ), 'data', ([('beference', ), ('aeference2', )], ))
 
216
        stream = builder.finish()
 
217
        contents = stream.read()
 
218
        self.assertEqual(
 
219
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=1\n"
 
220
            "aeference2\x00a\x00\x00\n"
 
221
            "beference\x00a\x00\x00\n"
 
222
            "rey\x00\x00074\r059\x00data\n"
 
223
            "\n", contents)
 
224
 
 
225
    def test_node_references_three_digits(self):
 
226
        # test the node digit expands as needed.
 
227
        builder = GraphIndexBuilder(reference_lists=1)
 
228
        references = [(str(val), ) for val in reversed(range(9))]
 
229
        builder.add_node(('2-key', ), '', (references, ))
 
230
        stream = builder.finish()
 
231
        contents = stream.read()
 
232
        self.assertEqual(
 
233
            "Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\nlen=1\n"
 
234
            "0\x00a\x00\x00\n"
 
235
            "1\x00a\x00\x00\n"
 
236
            "2\x00a\x00\x00\n"
 
237
            "2-key\x00\x00151\r145\r139\r133\r127\r121\r071\r065\r059\x00\n"
 
238
            "3\x00a\x00\x00\n"
 
239
            "4\x00a\x00\x00\n"
 
240
            "5\x00a\x00\x00\n"
 
241
            "6\x00a\x00\x00\n"
 
242
            "7\x00a\x00\x00\n"
 
243
            "8\x00a\x00\x00\n"
 
244
            "\n", contents)
 
245
 
 
246
    def test_absent_has_no_reference_overhead(self):
 
247
        # the offsets after an absent record should be correct when there are
 
248
        # >1 reference lists.
 
249
        builder = GraphIndexBuilder(reference_lists=2)
 
250
        builder.add_node(('parent', ), '', ([('aail', ), ('zther', )], []))
 
251
        stream = builder.finish()
 
252
        contents = stream.read()
 
253
        self.assertEqual(
 
254
            "Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\nlen=1\n"
 
255
            "aail\x00a\x00\x00\n"
 
256
            "parent\x00\x0059\r84\t\x00\n"
 
257
            "zther\x00a\x00\x00\n"
 
258
            "\n", contents)
 
259
 
 
260
    def test_add_node_bad_key(self):
 
261
        builder = GraphIndexBuilder()
 
262
        for bad_char in '\t\n\x0b\x0c\r\x00 ':
 
263
            self.assertRaises(errors.BadIndexKey, builder.add_node,
 
264
                ('a%skey' % bad_char, ), 'data')
 
265
        self.assertRaises(errors.BadIndexKey, builder.add_node,
 
266
                ('', ), 'data')
 
267
        self.assertRaises(errors.BadIndexKey, builder.add_node,
 
268
                'not-a-tuple', 'data')
 
269
        # not enough length
 
270
        self.assertRaises(errors.BadIndexKey, builder.add_node,
 
271
                (), 'data')
 
272
        # too long
 
273
        self.assertRaises(errors.BadIndexKey, builder.add_node,
 
274
                ('primary', 'secondary'), 'data')
 
275
        # secondary key elements get checked too:
 
276
        builder = GraphIndexBuilder(key_elements=2)
 
277
        for bad_char in '\t\n\x0b\x0c\r\x00 ':
 
278
            self.assertRaises(errors.BadIndexKey, builder.add_node,
 
279
                ('prefix', 'a%skey' % bad_char), 'data')
 
280
 
 
281
    def test_add_node_bad_data(self):
 
282
        builder = GraphIndexBuilder()
 
283
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
 
284
            'data\naa')
 
285
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
 
286
            'data\x00aa')
 
287
 
 
288
    def test_add_node_bad_mismatched_ref_lists_length(self):
 
289
        builder = GraphIndexBuilder()
 
290
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
 
291
            'data aa', ([], ))
 
292
        builder = GraphIndexBuilder(reference_lists=1)
 
293
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
 
294
            'data aa')
 
295
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
 
296
            'data aa', (), )
 
297
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
 
298
            'data aa', ([], []))
 
299
        builder = GraphIndexBuilder(reference_lists=2)
 
300
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
 
301
            'data aa')
 
302
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
 
303
            'data aa', ([], ))
 
304
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
 
305
            'data aa', ([], [], []))
 
306
 
 
307
    def test_add_node_bad_key_in_reference_lists(self):
 
308
        # first list, first key - trivial
 
309
        builder = GraphIndexBuilder(reference_lists=1)
 
310
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
 
311
            'data aa', ([('a key', )], ))
 
312
        # references keys must be tuples too
 
313
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
 
314
            'data aa', (['not-a-tuple'], ))
 
315
        # not enough length
 
316
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
 
317
            'data aa', ([()], ))
 
318
        # too long
 
319
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
 
320
            'data aa', ([('primary', 'secondary')], ))
 
321
        # need to check more than the first key in the list
 
322
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
 
323
            'data aa', ([('agoodkey', ), ('that is a bad key', )], ))
 
324
        # and if there is more than one list it should be getting checked
 
325
        # too
 
326
        builder = GraphIndexBuilder(reference_lists=2)
 
327
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
 
328
            'data aa', ([], ['a bad key']))
 
329
 
 
330
    def test_add_duplicate_key(self):
 
331
        builder = GraphIndexBuilder()
 
332
        builder.add_node(('key', ), 'data')
 
333
        self.assertRaises(errors.BadIndexDuplicateKey, builder.add_node, ('key', ),
 
334
            'data')
 
335
 
 
336
    def test_add_duplicate_key_2_elements(self):
 
337
        builder = GraphIndexBuilder(key_elements=2)
 
338
        builder.add_node(('key', 'key'), 'data')
 
339
        self.assertRaises(errors.BadIndexDuplicateKey, builder.add_node,
 
340
            ('key', 'key'), 'data')
 
341
 
 
342
    def test_add_key_after_referencing_key(self):
 
343
        builder = GraphIndexBuilder(reference_lists=1)
 
344
        builder.add_node(('key', ), 'data', ([('reference', )], ))
 
345
        builder.add_node(('reference', ), 'data', ([],))
 
346
 
 
347
    def test_add_key_after_referencing_key_2_elements(self):
 
348
        builder = GraphIndexBuilder(reference_lists=1, key_elements=2)
 
349
        builder.add_node(('k', 'ey'), 'data', ([('reference', 'tokey')], ))
 
350
        builder.add_node(('reference', 'tokey'), 'data', ([],))
 
351
 
 
352
 
 
353
class TestGraphIndex(TestCaseWithMemoryTransport):
 
354
 
 
355
    def make_index(self, ref_lists=0, key_elements=1, nodes=[]):
 
356
        builder = GraphIndexBuilder(ref_lists, key_elements=key_elements)
 
357
        for key, value, references in nodes:
 
358
            builder.add_node(key, value, references)
 
359
        stream = builder.finish()
 
360
        trans = self.get_transport()
 
361
        trans.put_file('index', stream)
 
362
        return GraphIndex(trans, 'index')
 
363
 
 
364
    def test_open_bad_index_no_error(self):
 
365
        trans = self.get_transport()
 
366
        trans.put_bytes('name', "not an index\n")
 
367
        index = GraphIndex(trans, 'name')
 
368
 
 
369
    def test_iter_all_entries_empty(self):
 
370
        index = self.make_index()
 
371
        self.assertEqual([], list(index.iter_all_entries()))
 
372
 
 
373
    def test_iter_all_entries_simple(self):
 
374
        index = self.make_index(nodes=[(('name', ), 'data', ())])
 
375
        self.assertEqual([(index, ('name', ), 'data')],
 
376
            list(index.iter_all_entries()))
 
377
 
 
378
    def test_iter_all_entries_simple_2_elements(self):
 
379
        index = self.make_index(key_elements=2,
 
380
            nodes=[(('name', 'surname'), 'data', ())])
 
381
        self.assertEqual([(index, ('name', 'surname'), 'data')],
 
382
            list(index.iter_all_entries()))
 
383
 
 
384
    def test_iter_all_entries_references_resolved(self):
 
385
        index = self.make_index(1, nodes=[
 
386
            (('name', ), 'data', ([('ref', )], )),
 
387
            (('ref', ), 'refdata', ([], ))])
 
388
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),)),
 
389
            (index, ('ref', ), 'refdata', ((), ))]),
 
390
            set(index.iter_all_entries()))
 
391
 
 
392
    def test_iteration_absent_skipped(self):
 
393
        index = self.make_index(1, nodes=[
 
394
            (('name', ), 'data', ([('ref', )], ))])
 
395
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),))]),
 
396
            set(index.iter_all_entries()))
 
397
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),))]),
 
398
            set(index.iter_entries([('name', )])))
 
399
        self.assertEqual([], list(index.iter_entries([('ref', )])))
 
400
 
 
401
    def test_iteration_absent_skipped_2_element_keys(self):
 
402
        index = self.make_index(1, key_elements=2, nodes=[
 
403
            (('name', 'fin'), 'data', ([('ref', 'erence')], ))])
 
404
        self.assertEqual(set([(index, ('name', 'fin'), 'data', ((('ref', 'erence'),),))]),
 
405
            set(index.iter_all_entries()))
 
406
        self.assertEqual(set([(index, ('name', 'fin'), 'data', ((('ref', 'erence'),),))]),
 
407
            set(index.iter_entries([('name', 'fin')])))
 
408
        self.assertEqual([], list(index.iter_entries([('ref', 'erence')])))
 
409
 
 
410
    def test_iter_all_keys(self):
 
411
        index = self.make_index(1, nodes=[
 
412
            (('name', ), 'data', ([('ref', )], )),
 
413
            (('ref', ), 'refdata', ([], ))])
 
414
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),)),
 
415
            (index, ('ref', ), 'refdata', ((), ))]),
 
416
            set(index.iter_entries([('name', ), ('ref', )])))
 
417
 
 
418
    def test_iter_nothing_empty(self):
 
419
        index = self.make_index()
 
420
        self.assertEqual([], list(index.iter_entries([])))
 
421
 
 
422
    def test_iter_missing_entry_empty(self):
 
423
        index = self.make_index()
 
424
        self.assertEqual([], list(index.iter_entries([('a', )])))
 
425
 
 
426
    def test_iter_key_prefix_1_element_key_None(self):
 
427
        index = self.make_index()
 
428
        self.assertRaises(errors.BadIndexKey, list,
 
429
            index.iter_entries_prefix([(None, )]))
 
430
 
 
431
    def test_iter_key_prefix_wrong_length(self):
 
432
        index = self.make_index()
 
433
        self.assertRaises(errors.BadIndexKey, list,
 
434
            index.iter_entries_prefix([('foo', None)]))
 
435
        index = self.make_index(key_elements=2)
 
436
        self.assertRaises(errors.BadIndexKey, list,
 
437
            index.iter_entries_prefix([('foo', )]))
 
438
        self.assertRaises(errors.BadIndexKey, list,
 
439
            index.iter_entries_prefix([('foo', None, None)]))
 
440
 
 
441
    def test_iter_key_prefix_1_key_element_no_refs(self):
 
442
        index = self.make_index( nodes=[
 
443
            (('name', ), 'data', ()),
 
444
            (('ref', ), 'refdata', ())])
 
445
        self.assertEqual(set([(index, ('name', ), 'data'),
 
446
            (index, ('ref', ), 'refdata')]),
 
447
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
 
448
 
 
449
    def test_iter_key_prefix_1_key_element_refs(self):
 
450
        index = self.make_index(1, nodes=[
 
451
            (('name', ), 'data', ([('ref', )], )),
 
452
            (('ref', ), 'refdata', ([], ))])
 
453
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),)),
 
454
            (index, ('ref', ), 'refdata', ((), ))]),
 
455
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
 
456
 
 
457
    def test_iter_key_prefix_2_key_element_no_refs(self):
 
458
        index = self.make_index(key_elements=2, nodes=[
 
459
            (('name', 'fin1'), 'data', ()),
 
460
            (('name', 'fin2'), 'beta', ()),
 
461
            (('ref', 'erence'), 'refdata', ())])
 
462
        self.assertEqual(set([(index, ('name', 'fin1'), 'data'),
 
463
            (index, ('ref', 'erence'), 'refdata')]),
 
464
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
 
465
        self.assertEqual(set([(index, ('name', 'fin1'), 'data'),
 
466
            (index, ('name', 'fin2'), 'beta')]),
 
467
            set(index.iter_entries_prefix([('name', None)])))
 
468
 
 
469
    def test_iter_key_prefix_2_key_element_refs(self):
 
470
        index = self.make_index(1, key_elements=2, nodes=[
 
471
            (('name', 'fin1'), 'data', ([('ref', 'erence')], )),
 
472
            (('name', 'fin2'), 'beta', ([], )),
 
473
            (('ref', 'erence'), 'refdata', ([], ))])
 
474
        self.assertEqual(set([(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
475
            (index, ('ref', 'erence'), 'refdata', ((), ))]),
 
476
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
 
477
        self.assertEqual(set([(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
478
            (index, ('name', 'fin2'), 'beta', ((), ))]),
 
479
            set(index.iter_entries_prefix([('name', None)])))
 
480
 
 
481
    def test_key_count_empty(self):
 
482
        index = self.make_index()
 
483
        self.assertEqual(0, index.key_count())
 
484
 
 
485
    def test_key_count_one(self):
 
486
        index = self.make_index(nodes=[(('name', ), '', ())])
 
487
        self.assertEqual(1, index.key_count())
 
488
 
 
489
    def test_key_count_two(self):
 
490
        index = self.make_index(nodes=[
 
491
            (('name', ), '', ()), (('foo', ), '', ())])
 
492
        self.assertEqual(2, index.key_count())
 
493
 
 
494
    def test_validate_bad_index_errors(self):
 
495
        trans = self.get_transport()
 
496
        trans.put_bytes('name', "not an index\n")
 
497
        index = GraphIndex(trans, 'name')
 
498
        self.assertRaises(errors.BadIndexFormatSignature, index.validate)
 
499
 
 
500
    def test_validate_bad_node_refs(self):
 
501
        index = self.make_index(2)
 
502
        trans = self.get_transport()
 
503
        content = trans.get_bytes('index')
 
504
        # change the options line to end with a rather than a parseable number
 
505
        new_content = content[:-2] + 'a\n\n'
 
506
        trans.put_bytes('index', new_content)
 
507
        self.assertRaises(errors.BadIndexOptions, index.validate)
 
508
 
 
509
    def test_validate_missing_end_line_empty(self):
 
510
        index = self.make_index(2)
 
511
        trans = self.get_transport()
 
512
        content = trans.get_bytes('index')
 
513
        # truncate the last byte
 
514
        trans.put_bytes('index', content[:-1])
 
515
        self.assertRaises(errors.BadIndexData, index.validate)
 
516
 
 
517
    def test_validate_missing_end_line_nonempty(self):
 
518
        index = self.make_index(2, nodes=[(('key', ), '', ([], []))])
 
519
        trans = self.get_transport()
 
520
        content = trans.get_bytes('index')
 
521
        # truncate the last byte
 
522
        trans.put_bytes('index', content[:-1])
 
523
        self.assertRaises(errors.BadIndexData, index.validate)
 
524
 
 
525
    def test_validate_empty(self):
 
526
        index = self.make_index()
 
527
        index.validate()
 
528
 
 
529
    def test_validate_no_refs_content(self):
 
530
        index = self.make_index(nodes=[(('key', ), 'value', ())])
 
531
        index.validate()
 
532
 
 
533
 
 
534
class TestCombinedGraphIndex(TestCaseWithMemoryTransport):
 
535
 
 
536
    def make_index(self, name, ref_lists=0, key_elements=1, nodes=[]):
 
537
        builder = GraphIndexBuilder(ref_lists, key_elements=key_elements)
 
538
        for key, value, references in nodes:
 
539
            builder.add_node(key, value, references)
 
540
        stream = builder.finish()
 
541
        trans = self.get_transport()
 
542
        trans.put_file(name, stream)
 
543
        return GraphIndex(trans, name)
 
544
 
 
545
    def test_open_missing_index_no_error(self):
 
546
        trans = self.get_transport()
 
547
        index1 = GraphIndex(trans, 'missing')
 
548
        index = CombinedGraphIndex([index1])
 
549
 
 
550
    def test_add_index(self):
 
551
        index = CombinedGraphIndex([])
 
552
        index1 = self.make_index('name', 0, nodes=[(('key', ), '', ())])
 
553
        index.insert_index(0, index1)
 
554
        self.assertEqual([(index1, ('key', ), '')], list(index.iter_all_entries()))
 
555
 
 
556
    def test_iter_all_entries_empty(self):
 
557
        index = CombinedGraphIndex([])
 
558
        self.assertEqual([], list(index.iter_all_entries()))
 
559
 
 
560
    def test_iter_all_entries_children_empty(self):
 
561
        index1 = self.make_index('name')
 
562
        index = CombinedGraphIndex([index1])
 
563
        self.assertEqual([], list(index.iter_all_entries()))
 
564
 
 
565
    def test_iter_all_entries_simple(self):
 
566
        index1 = self.make_index('name', nodes=[(('name', ), 'data', ())])
 
567
        index = CombinedGraphIndex([index1])
 
568
        self.assertEqual([(index1, ('name', ), 'data')],
 
569
            list(index.iter_all_entries()))
 
570
 
 
571
    def test_iter_all_entries_two_indices(self):
 
572
        index1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
 
573
        index2 = self.make_index('name2', nodes=[(('2', ), '', ())])
 
574
        index = CombinedGraphIndex([index1, index2])
 
575
        self.assertEqual([(index1, ('name', ), 'data'),
 
576
            (index2, ('2', ), '')],
 
577
            list(index.iter_all_entries()))
 
578
 
 
579
    def test_iter_entries_two_indices_dup_key(self):
 
580
        index1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
 
581
        index2 = self.make_index('name2', nodes=[(('name', ), 'data', ())])
 
582
        index = CombinedGraphIndex([index1, index2])
 
583
        self.assertEqual([(index1, ('name', ), 'data')],
 
584
            list(index.iter_entries([('name', )])))
 
585
 
 
586
    def test_iter_all_entries_two_indices_dup_key(self):
 
587
        index1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
 
588
        index2 = self.make_index('name2', nodes=[(('name', ), 'data', ())])
 
589
        index = CombinedGraphIndex([index1, index2])
 
590
        self.assertEqual([(index1, ('name', ), 'data')],
 
591
            list(index.iter_all_entries()))
 
592
 
 
593
    def test_iter_key_prefix_2_key_element_refs(self):
 
594
        index1 = self.make_index('1', 1, key_elements=2, nodes=[
 
595
            (('name', 'fin1'), 'data', ([('ref', 'erence')], ))])
 
596
        index2 = self.make_index('2', 1, key_elements=2, nodes=[
 
597
            (('name', 'fin2'), 'beta', ([], )),
 
598
            (('ref', 'erence'), 'refdata', ([], ))])
 
599
        index = CombinedGraphIndex([index1, index2])
 
600
        self.assertEqual(set([(index1, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
601
            (index2, ('ref', 'erence'), 'refdata', ((), ))]),
 
602
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
 
603
        self.assertEqual(set([(index1, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
604
            (index2, ('name', 'fin2'), 'beta', ((), ))]),
 
605
            set(index.iter_entries_prefix([('name', None)])))
 
606
 
 
607
    def test_iter_nothing_empty(self):
 
608
        index = CombinedGraphIndex([])
 
609
        self.assertEqual([], list(index.iter_entries([])))
 
610
 
 
611
    def test_iter_nothing_children_empty(self):
 
612
        index1 = self.make_index('name')
 
613
        index = CombinedGraphIndex([index1])
 
614
        self.assertEqual([], list(index.iter_entries([])))
 
615
 
 
616
    def test_iter_all_keys(self):
 
617
        index1 = self.make_index('1', 1, nodes=[
 
618
            (('name', ), 'data', ([('ref', )], ))])
 
619
        index2 = self.make_index('2', 1, nodes=[
 
620
            (('ref', ), 'refdata', ((), ))])
 
621
        index = CombinedGraphIndex([index1, index2])
 
622
        self.assertEqual(set([(index1, ('name', ), 'data', ((('ref', ), ), )),
 
623
            (index2, ('ref', ), 'refdata', ((), ))]),
 
624
            set(index.iter_entries([('name', ), ('ref', )])))
 
625
 
 
626
    def test_iter_all_keys_dup_entry(self):
 
627
        index1 = self.make_index('1', 1, nodes=[
 
628
            (('name', ), 'data', ([('ref', )], )),
 
629
            (('ref', ), 'refdata', ([], ))])
 
630
        index2 = self.make_index('2', 1, nodes=[
 
631
            (('ref', ), 'refdata', ([], ))])
 
632
        index = CombinedGraphIndex([index1, index2])
 
633
        self.assertEqual(set([(index1, ('name', ), 'data', ((('ref',),),)),
 
634
            (index1, ('ref', ), 'refdata', ((), ))]),
 
635
            set(index.iter_entries([('name', ), ('ref', )])))
 
636
 
 
637
    def test_iter_missing_entry_empty(self):
 
638
        index = CombinedGraphIndex([])
 
639
        self.assertEqual([], list(index.iter_entries([('a', )])))
 
640
 
 
641
    def test_iter_missing_entry_one_index(self):
 
642
        index1 = self.make_index('1')
 
643
        index = CombinedGraphIndex([index1])
 
644
        self.assertEqual([], list(index.iter_entries([('a', )])))
 
645
 
 
646
    def test_iter_missing_entry_two_index(self):
 
647
        index1 = self.make_index('1')
 
648
        index2 = self.make_index('2')
 
649
        index = CombinedGraphIndex([index1, index2])
 
650
        self.assertEqual([], list(index.iter_entries([('a', )])))
 
651
 
 
652
    def test_iter_entry_present_one_index_only(self):
 
653
        index1 = self.make_index('1', nodes=[(('key', ), '', ())])
 
654
        index2 = self.make_index('2', nodes=[])
 
655
        index = CombinedGraphIndex([index1, index2])
 
656
        self.assertEqual([(index1, ('key', ), '')],
 
657
            list(index.iter_entries([('key', )])))
 
658
        # and in the other direction
 
659
        index = CombinedGraphIndex([index2, index1])
 
660
        self.assertEqual([(index1, ('key', ), '')],
 
661
            list(index.iter_entries([('key', )])))
 
662
 
 
663
    def test_key_count_empty(self):
 
664
        index1 = self.make_index('1', nodes=[])
 
665
        index2 = self.make_index('2', nodes=[])
 
666
        index = CombinedGraphIndex([index1, index2])
 
667
        self.assertEqual(0, index.key_count())
 
668
 
 
669
    def test_key_count_sums_index_keys(self):
 
670
        index1 = self.make_index('1', nodes=[
 
671
            (('1',), '', ()),
 
672
            (('2',), '', ())])
 
673
        index2 = self.make_index('2', nodes=[(('1',), '', ())])
 
674
        index = CombinedGraphIndex([index1, index2])
 
675
        self.assertEqual(3, index.key_count())
 
676
 
 
677
    def test_validate_bad_child_index_errors(self):
 
678
        trans = self.get_transport()
 
679
        trans.put_bytes('name', "not an index\n")
 
680
        index1 = GraphIndex(trans, 'name')
 
681
        index = CombinedGraphIndex([index1])
 
682
        self.assertRaises(errors.BadIndexFormatSignature, index.validate)
 
683
 
 
684
    def test_validate_empty(self):
 
685
        index = CombinedGraphIndex([])
 
686
        index.validate()
 
687
 
 
688
 
 
689
class TestInMemoryGraphIndex(TestCaseWithMemoryTransport):
 
690
 
 
691
    def make_index(self, ref_lists=0, key_elements=1, nodes=[]):
 
692
        result = InMemoryGraphIndex(ref_lists, key_elements=key_elements)
 
693
        result.add_nodes(nodes)
 
694
        return result
 
695
 
 
696
    def test_add_nodes_no_refs(self):
 
697
        index = self.make_index(0)
 
698
        index.add_nodes([(('name', ), 'data')])
 
699
        index.add_nodes([(('name2', ), ''), (('name3', ), '')])
 
700
        self.assertEqual(set([
 
701
            (index, ('name', ), 'data'),
 
702
            (index, ('name2', ), ''),
 
703
            (index, ('name3', ), ''),
 
704
            ]), set(index.iter_all_entries()))
 
705
 
 
706
    def test_add_nodes(self):
 
707
        index = self.make_index(1)
 
708
        index.add_nodes([(('name', ), 'data', ([],))])
 
709
        index.add_nodes([(('name2', ), '', ([],)), (('name3', ), '', ([('r', )],))])
 
710
        self.assertEqual(set([
 
711
            (index, ('name', ), 'data', ((),)),
 
712
            (index, ('name2', ), '', ((),)),
 
713
            (index, ('name3', ), '', ((('r', ), ), )),
 
714
            ]), set(index.iter_all_entries()))
 
715
 
 
716
    def test_iter_all_entries_empty(self):
 
717
        index = self.make_index()
 
718
        self.assertEqual([], list(index.iter_all_entries()))
 
719
 
 
720
    def test_iter_all_entries_simple(self):
 
721
        index = self.make_index(nodes=[(('name', ), 'data')])
 
722
        self.assertEqual([(index, ('name', ), 'data')],
 
723
            list(index.iter_all_entries()))
 
724
 
 
725
    def test_iter_all_entries_references(self):
 
726
        index = self.make_index(1, nodes=[
 
727
            (('name', ), 'data', ([('ref', )], )),
 
728
            (('ref', ), 'refdata', ([], ))])
 
729
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref', ),),)),
 
730
            (index, ('ref', ), 'refdata', ((), ))]),
 
731
            set(index.iter_all_entries()))
 
732
 
 
733
    def test_iteration_absent_skipped(self):
 
734
        index = self.make_index(1, nodes=[
 
735
            (('name', ), 'data', ([('ref', )], ))])
 
736
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),))]),
 
737
            set(index.iter_all_entries()))
 
738
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),))]),
 
739
            set(index.iter_entries([('name', )])))
 
740
        self.assertEqual([], list(index.iter_entries([('ref', )])))
 
741
 
 
742
    def test_iter_all_keys(self):
 
743
        index = self.make_index(1, nodes=[
 
744
            (('name', ), 'data', ([('ref', )], )),
 
745
            (('ref', ), 'refdata', ([], ))])
 
746
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),)),
 
747
            (index, ('ref', ), 'refdata', ((), ))]),
 
748
            set(index.iter_entries([('name', ), ('ref', )])))
 
749
 
 
750
    def test_iter_key_prefix_1_key_element_no_refs(self):
 
751
        index = self.make_index( nodes=[
 
752
            (('name', ), 'data'),
 
753
            (('ref', ), 'refdata')])
 
754
        self.assertEqual(set([(index, ('name', ), 'data'),
 
755
            (index, ('ref', ), 'refdata')]),
 
756
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
 
757
 
 
758
    def test_iter_key_prefix_1_key_element_refs(self):
 
759
        index = self.make_index(1, nodes=[
 
760
            (('name', ), 'data', ([('ref', )], )),
 
761
            (('ref', ), 'refdata', ([], ))])
 
762
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),)),
 
763
            (index, ('ref', ), 'refdata', ((), ))]),
 
764
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
 
765
 
 
766
    def test_iter_key_prefix_2_key_element_no_refs(self):
 
767
        index = self.make_index(key_elements=2, nodes=[
 
768
            (('name', 'fin1'), 'data'),
 
769
            (('name', 'fin2'), 'beta'),
 
770
            (('ref', 'erence'), 'refdata')])
 
771
        self.assertEqual(set([(index, ('name', 'fin1'), 'data'),
 
772
            (index, ('ref', 'erence'), 'refdata')]),
 
773
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
 
774
        self.assertEqual(set([(index, ('name', 'fin1'), 'data'),
 
775
            (index, ('name', 'fin2'), 'beta')]),
 
776
            set(index.iter_entries_prefix([('name', None)])))
 
777
 
 
778
    def test_iter_key_prefix_2_key_element_refs(self):
 
779
        index = self.make_index(1, key_elements=2, nodes=[
 
780
            (('name', 'fin1'), 'data', ([('ref', 'erence')], )),
 
781
            (('name', 'fin2'), 'beta', ([], )),
 
782
            (('ref', 'erence'), 'refdata', ([], ))])
 
783
        self.assertEqual(set([(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
784
            (index, ('ref', 'erence'), 'refdata', ((), ))]),
 
785
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
 
786
        self.assertEqual(set([(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
787
            (index, ('name', 'fin2'), 'beta', ((), ))]),
 
788
            set(index.iter_entries_prefix([('name', None)])))
 
789
 
 
790
    def test_iter_nothing_empty(self):
 
791
        index = self.make_index()
 
792
        self.assertEqual([], list(index.iter_entries([])))
 
793
 
 
794
    def test_iter_missing_entry_empty(self):
 
795
        index = self.make_index()
 
796
        self.assertEqual([], list(index.iter_entries(['a'])))
 
797
 
 
798
    def test_key_count_empty(self):
 
799
        index = self.make_index()
 
800
        self.assertEqual(0, index.key_count())
 
801
 
 
802
    def test_key_count_one(self):
 
803
        index = self.make_index(nodes=[(('name', ), '')])
 
804
        self.assertEqual(1, index.key_count())
 
805
 
 
806
    def test_key_count_two(self):
 
807
        index = self.make_index(nodes=[(('name', ), ''), (('foo', ), '')])
 
808
        self.assertEqual(2, index.key_count())
 
809
 
 
810
    def test_validate_empty(self):
 
811
        index = self.make_index()
 
812
        index.validate()
 
813
 
 
814
    def test_validate_no_refs_content(self):
 
815
        index = self.make_index(nodes=[(('key', ), 'value')])
 
816
        index.validate()
 
817
 
 
818
 
 
819
class TestGraphIndexPrefixAdapter(TestCaseWithMemoryTransport):
 
820
 
 
821
    def make_index(self, ref_lists=1, key_elements=2, nodes=[], add_callback=False):
 
822
        result = InMemoryGraphIndex(ref_lists, key_elements=key_elements)
 
823
        result.add_nodes(nodes)
 
824
        if add_callback:
 
825
            add_nodes_callback = result.add_nodes
 
826
        else:
 
827
            add_nodes_callback = None
 
828
        adapter = GraphIndexPrefixAdapter(result, ('prefix', ), key_elements - 1,
 
829
            add_nodes_callback=add_nodes_callback)
 
830
        return result, adapter
 
831
 
 
832
    def test_add_node(self):
 
833
        index, adapter = self.make_index(add_callback=True)
 
834
        adapter.add_node(('key',), 'value', ((('ref',),),))
 
835
        self.assertEqual(set([(index, ('prefix', 'key'), 'value', ((('prefix', 'ref'),),))]),
 
836
            set(index.iter_all_entries()))
 
837
 
 
838
    def test_add_nodes(self):
 
839
        index, adapter = self.make_index(add_callback=True)
 
840
        adapter.add_nodes((
 
841
            (('key',), 'value', ((('ref',),),)),
 
842
            (('key2',), 'value2', ((),)),
 
843
            ))
 
844
        self.assertEqual(set([
 
845
            (index, ('prefix', 'key2'), 'value2', ((),)),
 
846
            (index, ('prefix', 'key'), 'value', ((('prefix', 'ref'),),))
 
847
            ]),
 
848
            set(index.iter_all_entries()))
 
849
 
 
850
    def test_construct(self):
 
851
        index = InMemoryGraphIndex()
 
852
        adapter = GraphIndexPrefixAdapter(index, ('prefix', ), 1)
 
853
 
 
854
    def test_construct_with_callback(self):
 
855
        index = InMemoryGraphIndex()
 
856
        adapter = GraphIndexPrefixAdapter(index, ('prefix', ), 1, index.add_nodes)
 
857
 
 
858
    def test_iter_all_entries_cross_prefix_map_errors(self):
 
859
        index, adapter = self.make_index(nodes=[
 
860
            (('prefix', 'key1'), 'data1', ((('prefixaltered', 'key2'),),))])
 
861
        self.assertRaises(errors.BadIndexData, list, adapter.iter_all_entries())
 
862
 
 
863
    def test_iter_all_entries(self):
 
864
        index, adapter = self.make_index(nodes=[
 
865
            (('notprefix', 'key1'), 'data', ((), )),
 
866
            (('prefix', 'key1'), 'data1', ((), )),
 
867
            (('prefix', 'key2'), 'data2', ((('prefix', 'key1'),),))])
 
868
        self.assertEqual(set([(index, ('key1', ), 'data1', ((),)),
 
869
            (index, ('key2', ), 'data2', ((('key1',),),))]),
 
870
            set(adapter.iter_all_entries()))
 
871
 
 
872
    def test_iter_entries(self):
 
873
        index, adapter = self.make_index(nodes=[
 
874
            (('notprefix', 'key1'), 'data', ((), )),
 
875
            (('prefix', 'key1'), 'data1', ((), )),
 
876
            (('prefix', 'key2'), 'data2', ((('prefix', 'key1'),),))])
 
877
        # ask for many - get all
 
878
        self.assertEqual(set([(index, ('key1', ), 'data1', ((),)),
 
879
            (index, ('key2', ), 'data2', ((('key1', ),),))]),
 
880
            set(adapter.iter_entries([('key1', ), ('key2', )])))
 
881
        # ask for one, get one
 
882
        self.assertEqual(set([(index, ('key1', ), 'data1', ((),))]),
 
883
            set(adapter.iter_entries([('key1', )])))
 
884
        # ask for missing, get none
 
885
        self.assertEqual(set(),
 
886
            set(adapter.iter_entries([('key3', )])))
 
887
 
 
888
    def test_iter_entries_prefix(self):
 
889
        index, adapter = self.make_index(key_elements=3, nodes=[
 
890
            (('notprefix', 'foo', 'key1'), 'data', ((), )),
 
891
            (('prefix', 'prefix2', 'key1'), 'data1', ((), )),
 
892
            (('prefix', 'prefix2', 'key2'), 'data2', ((('prefix', 'prefix2', 'key1'),),))])
 
893
        # ask for a prefix, get the results for just that prefix, adjusted.
 
894
        self.assertEqual(set([(index, ('prefix2', 'key1', ), 'data1', ((),)),
 
895
            (index, ('prefix2', 'key2', ), 'data2', ((('prefix2', 'key1', ),),))]),
 
896
            set(adapter.iter_entries_prefix([('prefix2', None)])))
 
897
 
 
898
    def test_key_count_no_matching_keys(self):
 
899
        index, adapter = self.make_index(nodes=[
 
900
            (('notprefix', 'key1'), 'data', ((), ))])
 
901
        self.assertEqual(0, adapter.key_count())
 
902
 
 
903
    def test_key_count_some_keys(self):
 
904
        index, adapter = self.make_index(nodes=[
 
905
            (('notprefix', 'key1'), 'data', ((), )),
 
906
            (('prefix', 'key1'), 'data1', ((), )),
 
907
            (('prefix', 'key2'), 'data2', ((('prefix', 'key1'),),))])
 
908
        self.assertEqual(2, adapter.key_count())
 
909
 
 
910
    def test_validate(self):
 
911
        index, adapter = self.make_index()
 
912
        calls = []
 
913
        def validate():
 
914
            calls.append('called')
 
915
        index.validate = validate
 
916
        adapter.validate()
 
917
        self.assertEqual(['called'], calls)