~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_index.py

Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
        builder = GraphIndexBuilder()
28
28
        stream = builder.finish()
29
29
        contents = stream.read()
30
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\n\n", contents)
 
30
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\n\n", contents)
 
31
 
 
32
    def test_build_index_empty_two_element_keys(self):
 
33
        builder = GraphIndexBuilder(key_elements=2)
 
34
        stream = builder.finish()
 
35
        contents = stream.read()
 
36
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=2\n\n", contents)
31
37
 
32
38
    def test_build_index_one_reference_list_empty(self):
33
39
        builder = GraphIndexBuilder(reference_lists=1)
34
40
        stream = builder.finish()
35
41
        contents = stream.read()
36
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n\n", contents)
 
42
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n\n", contents)
37
43
 
38
44
    def test_build_index_two_reference_list_empty(self):
39
45
        builder = GraphIndexBuilder(reference_lists=2)
40
46
        stream = builder.finish()
41
47
        contents = stream.read()
42
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\n\n", contents)
 
48
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\n\n", contents)
43
49
 
44
50
    def test_build_index_one_node_no_refs(self):
45
51
        builder = GraphIndexBuilder()
46
 
        builder.add_node('akey', 'data')
 
52
        builder.add_node(('akey', ), 'data')
47
53
        stream = builder.finish()
48
54
        contents = stream.read()
49
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\n"
 
55
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\n"
50
56
            "akey\x00\x00\x00data\n\n", contents)
51
57
 
52
58
    def test_build_index_one_node_no_refs_accepts_empty_reflist(self):
53
59
        builder = GraphIndexBuilder()
54
 
        builder.add_node('akey', 'data', ())
 
60
        builder.add_node(('akey', ), 'data', ())
55
61
        stream = builder.finish()
56
62
        contents = stream.read()
57
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\n"
 
63
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\n"
58
64
            "akey\x00\x00\x00data\n\n", contents)
59
65
 
 
66
    def test_build_index_one_node_2_element_keys(self):
 
67
        # multipart keys are separated by \x00 - because they are fixed length,
 
68
        # not variable this does not cause any issues, and seems clearer to the
 
69
        # author.
 
70
        builder = GraphIndexBuilder(key_elements=2)
 
71
        builder.add_node(('akey', 'secondpart'), 'data')
 
72
        stream = builder.finish()
 
73
        contents = stream.read()
 
74
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=2\n"
 
75
            "akey\x00secondpart\x00\x00\x00data\n\n", contents)
 
76
 
60
77
    def test_add_node_empty_value(self):
61
78
        builder = GraphIndexBuilder()
62
 
        builder.add_node('akey', '')
 
79
        builder.add_node(('akey', ), '')
63
80
        stream = builder.finish()
64
81
        contents = stream.read()
65
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\n"
 
82
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\n"
66
83
            "akey\x00\x00\x00\n\n", contents)
67
84
 
68
 
    def test_build_index_two_nodes_sorted(self):
 
85
    def test_build_index_nodes_sorted(self):
69
86
        # the highest sorted node comes first.
70
87
        builder = GraphIndexBuilder()
71
88
        # use three to have a good chance of glitching dictionary hash
72
89
        # lookups etc. Insert in randomish order that is not correct
73
90
        # and not the reverse of the correct order.
74
 
        builder.add_node('2002', 'data')
75
 
        builder.add_node('2000', 'data')
76
 
        builder.add_node('2001', 'data')
 
91
        builder.add_node(('2002', ), 'data')
 
92
        builder.add_node(('2000', ), 'data')
 
93
        builder.add_node(('2001', ), 'data')
77
94
        stream = builder.finish()
78
95
        contents = stream.read()
79
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\n"
 
96
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\n"
80
97
            "2000\x00\x00\x00data\n"
81
98
            "2001\x00\x00\x00data\n"
82
99
            "2002\x00\x00\x00data\n"
83
100
            "\n", contents)
84
101
 
 
102
    def test_build_index_2_element_key_nodes_sorted(self):
 
103
        # multiple element keys are sorted first-key, second-key.
 
104
        builder = GraphIndexBuilder(key_elements=2)
 
105
        # use three values of each key element, to have a good chance of
 
106
        # glitching dictionary hash lookups etc. Insert in randomish order that
 
107
        # is not correct and not the reverse of the correct order.
 
108
        builder.add_node(('2002', '2002'), 'data')
 
109
        builder.add_node(('2002', '2000'), 'data')
 
110
        builder.add_node(('2002', '2001'), 'data')
 
111
        builder.add_node(('2000', '2002'), 'data')
 
112
        builder.add_node(('2000', '2000'), 'data')
 
113
        builder.add_node(('2000', '2001'), 'data')
 
114
        builder.add_node(('2001', '2002'), 'data')
 
115
        builder.add_node(('2001', '2000'), 'data')
 
116
        builder.add_node(('2001', '2001'), 'data')
 
117
        stream = builder.finish()
 
118
        contents = stream.read()
 
119
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=2\n"
 
120
            "2000\x002000\x00\x00\x00data\n"
 
121
            "2000\x002001\x00\x00\x00data\n"
 
122
            "2000\x002002\x00\x00\x00data\n"
 
123
            "2001\x002000\x00\x00\x00data\n"
 
124
            "2001\x002001\x00\x00\x00data\n"
 
125
            "2001\x002002\x00\x00\x00data\n"
 
126
            "2002\x002000\x00\x00\x00data\n"
 
127
            "2002\x002001\x00\x00\x00data\n"
 
128
            "2002\x002002\x00\x00\x00data\n"
 
129
            "\n", contents)
 
130
 
85
131
    def test_build_index_reference_lists_are_included_one(self):
86
132
        builder = GraphIndexBuilder(reference_lists=1)
87
 
        builder.add_node('key', 'data', ([], ))
 
133
        builder.add_node(('key', ), 'data', ([], ))
88
134
        stream = builder.finish()
89
135
        contents = stream.read()
90
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n"
 
136
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n"
91
137
            "key\x00\x00\x00data\n"
92
138
            "\n", contents)
93
139
 
 
140
    def test_build_index_reference_lists_with_2_element_keys(self):
 
141
        builder = GraphIndexBuilder(reference_lists=1, key_elements=2)
 
142
        builder.add_node(('key', 'key2'), 'data', ([], ))
 
143
        stream = builder.finish()
 
144
        contents = stream.read()
 
145
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=2\n"
 
146
            "key\x00key2\x00\x00\x00data\n"
 
147
            "\n", contents)
 
148
 
94
149
    def test_build_index_reference_lists_are_included_two(self):
95
150
        builder = GraphIndexBuilder(reference_lists=2)
96
 
        builder.add_node('key', 'data', ([], []))
 
151
        builder.add_node(('key', ), 'data', ([], []))
97
152
        stream = builder.finish()
98
153
        contents = stream.read()
99
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\n"
 
154
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\n"
100
155
            "key\x00\x00\t\x00data\n"
101
156
            "\n", contents)
102
157
 
103
158
    def test_node_references_are_byte_offsets(self):
104
159
        builder = GraphIndexBuilder(reference_lists=1)
105
 
        builder.add_node('reference', 'data', ([], ))
106
 
        builder.add_node('key', 'data', (['reference'], ))
 
160
        builder.add_node(('reference', ), 'data', ([], ))
 
161
        builder.add_node(('key', ), 'data', ([('reference', )], ))
107
162
        stream = builder.finish()
108
163
        contents = stream.read()
109
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n"
110
 
            "key\x00\x0051\x00data\n"
 
164
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n"
 
165
            "key\x00\x0066\x00data\n"
111
166
            "reference\x00\x00\x00data\n"
112
167
            "\n", contents)
113
168
 
114
169
    def test_node_references_are_cr_delimited(self):
115
170
        builder = GraphIndexBuilder(reference_lists=1)
116
 
        builder.add_node('reference', 'data', ([], ))
117
 
        builder.add_node('reference2', 'data', ([], ))
118
 
        builder.add_node('key', 'data', (['reference', 'reference2'], ))
 
171
        builder.add_node(('reference', ), 'data', ([], ))
 
172
        builder.add_node(('reference2', ), 'data', ([], ))
 
173
        builder.add_node(('key', ), 'data', ([('reference', ), ('reference2', )], ))
119
174
        stream = builder.finish()
120
175
        contents = stream.read()
121
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n"
122
 
            "key\x00\x0054\r71\x00data\n"
 
176
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n"
 
177
            "key\x00\x00071\r088\x00data\n"
123
178
            "reference\x00\x00\x00data\n"
124
179
            "reference2\x00\x00\x00data\n"
125
180
            "\n", contents)
126
181
 
127
182
    def test_multiple_reference_lists_are_tab_delimited(self):
128
183
        builder = GraphIndexBuilder(reference_lists=2)
129
 
        builder.add_node('keference', 'data', ([], []))
130
 
        builder.add_node('rey', 'data', (['keference'], ['keference']))
 
184
        builder.add_node(('keference', ), 'data', ([], []))
 
185
        builder.add_node(('rey', ), 'data', ([('keference', )], [('keference', )]))
131
186
        stream = builder.finish()
132
187
        contents = stream.read()
133
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\n"
 
188
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\n"
134
189
            "keference\x00\x00\t\x00data\n"
135
 
            "rey\x00\x0038\t38\x00data\n"
 
190
            "rey\x00\x0053\t53\x00data\n"
136
191
            "\n", contents)
137
192
 
138
193
    def test_add_node_referencing_missing_key_makes_absent(self):
139
194
        builder = GraphIndexBuilder(reference_lists=1)
140
 
        builder.add_node('rey', 'data', (['beference', 'aeference2'], ))
 
195
        builder.add_node(('rey', ), 'data', ([('beference', ), ('aeference2', )], ))
141
196
        stream = builder.finish()
142
197
        contents = stream.read()
143
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n"
 
198
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n"
144
199
            "aeference2\x00a\x00\x00\n"
145
200
            "beference\x00a\x00\x00\n"
146
 
            "rey\x00\x0053\r38\x00data\n"
 
201
            "rey\x00\x0068\r53\x00data\n"
147
202
            "\n", contents)
148
203
 
149
204
    def test_node_references_three_digits(self):
150
205
        # test the node digit expands as needed.
151
206
        builder = GraphIndexBuilder(reference_lists=1)
152
 
        references = map(str, reversed(range(9)))
153
 
        builder.add_node('2-key', '', (references, ))
 
207
        references = [(str(val), ) for val in reversed(range(9))]
 
208
        builder.add_node(('2-key', ), '', (references, ))
154
209
        stream = builder.finish()
155
210
        contents = stream.read()
156
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\n"
 
211
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n"
157
212
            "0\x00a\x00\x00\n"
158
213
            "1\x00a\x00\x00\n"
159
214
            "2\x00a\x00\x00\n"
160
 
            "2-key\x00\x00130\r124\r118\r112\r106\r100\r050\r044\r038\x00\n"
 
215
            "2-key\x00\x00145\r139\r133\r127\r121\r115\r065\r059\r053\x00\n"
161
216
            "3\x00a\x00\x00\n"
162
217
            "4\x00a\x00\x00\n"
163
218
            "5\x00a\x00\x00\n"
170
225
        # the offsets after an absent record should be correct when there are
171
226
        # >1 reference lists.
172
227
        builder = GraphIndexBuilder(reference_lists=2)
173
 
        builder.add_node('parent', '', (['aail', 'zther'], []))
 
228
        builder.add_node(('parent', ), '', ([('aail', ), ('zther', )], []))
174
229
        stream = builder.finish()
175
230
        contents = stream.read()
176
 
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\n"
 
231
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\n"
177
232
            "aail\x00a\x00\x00\n"
178
 
            "parent\x00\x0038\r63\t\x00\n"
 
233
            "parent\x00\x0053\r78\t\x00\n"
179
234
            "zther\x00a\x00\x00\n"
180
235
            "\n", contents)
181
236
 
183
238
        builder = GraphIndexBuilder()
184
239
        for bad_char in '\t\n\x0b\x0c\r\x00 ':
185
240
            self.assertRaises(errors.BadIndexKey, builder.add_node,
186
 
                'a%skey' % bad_char, 'data')
187
 
        self.assertRaises(errors.BadIndexKey, builder.add_node,
188
 
                '', 'data')
 
241
                ('a%skey' % bad_char, ), 'data')
 
242
        self.assertRaises(errors.BadIndexKey, builder.add_node,
 
243
                ('', ), 'data')
 
244
        self.assertRaises(errors.BadIndexKey, builder.add_node,
 
245
                'not-a-tuple', 'data')
 
246
        # not enough length
 
247
        self.assertRaises(errors.BadIndexKey, builder.add_node,
 
248
                (), 'data')
 
249
        # too long
 
250
        self.assertRaises(errors.BadIndexKey, builder.add_node,
 
251
                ('primary', 'secondary'), 'data')
 
252
        # secondary key elements get checked too:
 
253
        builder = GraphIndexBuilder(key_elements=2)
 
254
        for bad_char in '\t\n\x0b\x0c\r\x00 ':
 
255
            self.assertRaises(errors.BadIndexKey, builder.add_node,
 
256
                ('prefix', 'a%skey' % bad_char), 'data')
189
257
 
190
258
    def test_add_node_bad_data(self):
191
259
        builder = GraphIndexBuilder()
192
 
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
 
260
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
193
261
            'data\naa')
194
 
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
 
262
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
195
263
            'data\x00aa')
196
264
 
197
265
    def test_add_node_bad_mismatched_ref_lists_length(self):
198
266
        builder = GraphIndexBuilder()
199
 
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
 
267
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
200
268
            'data aa', ([], ))
201
269
        builder = GraphIndexBuilder(reference_lists=1)
202
 
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
 
270
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
203
271
            'data aa')
204
 
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
 
272
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
205
273
            'data aa', (), )
206
 
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
 
274
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
207
275
            'data aa', ([], []))
208
276
        builder = GraphIndexBuilder(reference_lists=2)
209
 
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
 
277
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
210
278
            'data aa')
211
 
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
 
279
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
212
280
            'data aa', ([], ))
213
 
        self.assertRaises(errors.BadIndexValue, builder.add_node, 'akey',
 
281
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
214
282
            'data aa', ([], [], []))
215
283
 
216
284
    def test_add_node_bad_key_in_reference_lists(self):
217
285
        # first list, first key - trivial
218
286
        builder = GraphIndexBuilder(reference_lists=1)
219
 
        self.assertRaises(errors.BadIndexKey, builder.add_node, 'akey',
220
 
            'data aa', (['a key'], ))
 
287
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
 
288
            'data aa', ([('a key', )], ))
 
289
        # references keys must be tuples too
 
290
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
 
291
            'data aa', (['not-a-tuple'], ))
 
292
        # not enough length
 
293
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
 
294
            'data aa', ([()], ))
 
295
        # too long
 
296
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
 
297
            'data aa', ([('primary', 'secondary')], ))
221
298
        # need to check more than the first key in the list
222
 
        self.assertRaises(errors.BadIndexKey, builder.add_node, 'akey',
223
 
            'data aa', (['agoodkey', 'this is a bad key'], ))
 
299
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
 
300
            'data aa', ([('agoodkey', ), ('that is a bad key', )], ))
224
301
        # and if there is more than one list it should be getting checked
225
302
        # too
226
303
        builder = GraphIndexBuilder(reference_lists=2)
227
 
        self.assertRaises(errors.BadIndexKey, builder.add_node, 'akey',
 
304
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
228
305
            'data aa', ([], ['a bad key']))
229
306
 
230
307
    def test_add_duplicate_key(self):
231
308
        builder = GraphIndexBuilder()
232
 
        builder.add_node('key', 'data')
233
 
        self.assertRaises(errors.BadIndexDuplicateKey, builder.add_node, 'key',
 
309
        builder.add_node(('key', ), 'data')
 
310
        self.assertRaises(errors.BadIndexDuplicateKey, builder.add_node, ('key', ),
234
311
            'data')
235
312
 
 
313
    def test_add_duplicate_key_2_elements(self):
 
314
        builder = GraphIndexBuilder(key_elements=2)
 
315
        builder.add_node(('key', 'key'), 'data')
 
316
        self.assertRaises(errors.BadIndexDuplicateKey, builder.add_node,
 
317
            ('key', 'key'), 'data')
 
318
 
236
319
    def test_add_key_after_referencing_key(self):
237
320
        builder = GraphIndexBuilder(reference_lists=1)
238
 
        builder.add_node('key', 'data', (['reference'], ))
239
 
        builder.add_node('reference', 'data', ([],))
 
321
        builder.add_node(('key', ), 'data', ([('reference', )], ))
 
322
        builder.add_node(('reference', ), 'data', ([],))
 
323
 
 
324
    def test_add_key_after_referencing_key_2_elements(self):
 
325
        builder = GraphIndexBuilder(reference_lists=1, key_elements=2)
 
326
        builder.add_node(('k', 'ey'), 'data', ([('reference', 'tokey')], ))
 
327
        builder.add_node(('reference', 'tokey'), 'data', ([],))
240
328
 
241
329
 
242
330
class TestGraphIndex(TestCaseWithMemoryTransport):
243
331
 
244
 
    def make_index(self, ref_lists=0, nodes=[]):
245
 
        builder = GraphIndexBuilder(ref_lists)
 
332
    def make_index(self, ref_lists=0, key_elements=1, nodes=[]):
 
333
        builder = GraphIndexBuilder(ref_lists, key_elements=key_elements)
246
334
        for node, value, references in nodes:
247
335
            builder.add_node(node, value, references)
248
336
        stream = builder.finish()
260
348
        self.assertEqual([], list(index.iter_all_entries()))
261
349
 
262
350
    def test_iter_all_entries_simple(self):
263
 
        index = self.make_index(nodes=[('name', 'data', ())])
264
 
        self.assertEqual([('name', 'data')],
 
351
        index = self.make_index(nodes=[(('name', ), 'data', ())])
 
352
        self.assertEqual([(('name', ), 'data')],
 
353
            list(index.iter_all_entries()))
 
354
 
 
355
    def test_iter_all_entries_simple_2_elements(self):
 
356
        index = self.make_index(key_elements=2,
 
357
            nodes=[(('name', 'surname'), 'data', ())])
 
358
        self.assertEqual([(('name', 'surname'), 'data')],
265
359
            list(index.iter_all_entries()))
266
360
 
267
361
    def test_iter_all_entries_references_resolved(self):
268
362
        index = self.make_index(1, nodes=[
269
 
            ('name', 'data', (['ref'], )),
270
 
            ('ref', 'refdata', ([], ))])
271
 
        self.assertEqual(set([('name', 'data', (('ref',),)),
272
 
            ('ref', 'refdata', ((), ))]),
 
363
            (('name', ), 'data', ([('ref', )], )),
 
364
            (('ref', ), 'refdata', ([], ))])
 
365
        self.assertEqual(set([(('name', ), 'data', ((('ref',),),)),
 
366
            (('ref', ), 'refdata', ((), ))]),
273
367
            set(index.iter_all_entries()))
274
368
 
275
369
    def test_iteration_absent_skipped(self):
276
370
        index = self.make_index(1, nodes=[
277
 
            ('name', 'data', (['ref'], ))])
278
 
        self.assertEqual(set([('name', 'data', (('ref',),))]),
279
 
            set(index.iter_all_entries()))
280
 
        self.assertEqual(set([('name', 'data', (('ref',),))]),
281
 
            set(index.iter_entries(['name'])))
282
 
        self.assertEqual([], list(index.iter_entries(['ref'])))
 
371
            (('name', ), 'data', ([('ref', )], ))])
 
372
        self.assertEqual(set([(('name', ), 'data', ((('ref',),),))]),
 
373
            set(index.iter_all_entries()))
 
374
        self.assertEqual(set([(('name', ), 'data', ((('ref',),),))]),
 
375
            set(index.iter_entries([('name', )])))
 
376
        self.assertEqual([], list(index.iter_entries([('ref', )])))
 
377
 
 
378
    def test_iteration_absent_skipped_2_element_keys(self):
 
379
        index = self.make_index(1, key_elements=2, nodes=[
 
380
            (('name', 'fin'), 'data', ([('ref', 'erence')], ))])
 
381
        self.assertEqual(set([(('name', 'fin'), 'data', ((('ref', 'erence'),),))]),
 
382
            set(index.iter_all_entries()))
 
383
        self.assertEqual(set([(('name', 'fin'), 'data', ((('ref', 'erence'),),))]),
 
384
            set(index.iter_entries([('name', 'fin')])))
 
385
        self.assertEqual([], list(index.iter_entries([('ref', 'erence')])))
283
386
 
284
387
    def test_iter_all_keys(self):
285
388
        index = self.make_index(1, nodes=[
286
 
            ('name', 'data', (['ref'], )),
287
 
            ('ref', 'refdata', ([], ))])
288
 
        self.assertEqual(set([('name', 'data', (('ref',),)),
289
 
            ('ref', 'refdata', ((), ))]),
290
 
            set(index.iter_entries(['name', 'ref'])))
 
389
            (('name', ), 'data', ([('ref', )], )),
 
390
            (('ref', ), 'refdata', ([], ))])
 
391
        self.assertEqual(set([(('name', ), 'data', ((('ref',),),)),
 
392
            (('ref', ), 'refdata', ((), ))]),
 
393
            set(index.iter_entries([('name', ), ('ref', )])))
291
394
 
292
395
    def test_iter_nothing_empty(self):
293
396
        index = self.make_index()
295
398
 
296
399
    def test_iter_missing_entry_empty(self):
297
400
        index = self.make_index()
298
 
        self.assertEqual([], list(index.iter_entries(['a'])))
 
401
        self.assertEqual([], list(index.iter_entries([('a', )])))
 
402
 
 
403
    def test_iter_key_prefix_1_element_key_None(self):
 
404
        index = self.make_index()
 
405
        self.assertRaises(errors.BadIndexKey, list,
 
406
            index.iter_entries_prefix([(None, )]))
 
407
 
 
408
    def test_iter_key_prefix_wrong_length(self):
 
409
        index = self.make_index()
 
410
        self.assertRaises(errors.BadIndexKey, list,
 
411
            index.iter_entries_prefix([('foo', None)]))
 
412
        index = self.make_index(key_elements=2)
 
413
        self.assertRaises(errors.BadIndexKey, list,
 
414
            index.iter_entries_prefix([('foo', )]))
 
415
        self.assertRaises(errors.BadIndexKey, list,
 
416
            index.iter_entries_prefix([('foo', None, None)]))
 
417
 
 
418
    def test_iter_key_prefix_1_key_element_no_refs(self):
 
419
        index = self.make_index( nodes=[
 
420
            (('name', ), 'data', ()),
 
421
            (('ref', ), 'refdata', ())])
 
422
        self.assertEqual(set([(('name', ), 'data'),
 
423
            (('ref', ), 'refdata')]),
 
424
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
 
425
 
 
426
    def test_iter_key_prefix_1_key_element_refs(self):
 
427
        index = self.make_index(1, nodes=[
 
428
            (('name', ), 'data', ([('ref', )], )),
 
429
            (('ref', ), 'refdata', ([], ))])
 
430
        self.assertEqual(set([(('name', ), 'data', ((('ref',),),)),
 
431
            (('ref', ), 'refdata', ((), ))]),
 
432
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
 
433
 
 
434
    def test_iter_key_prefix_2_key_element_no_refs(self):
 
435
        index = self.make_index(key_elements=2, nodes=[
 
436
            (('name', 'fin1'), 'data', ()),
 
437
            (('name', 'fin2'), 'beta', ()),
 
438
            (('ref', 'erence'), 'refdata', ())])
 
439
        self.assertEqual(set([(('name', 'fin1'), 'data'),
 
440
            (('ref', 'erence'), 'refdata')]),
 
441
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
 
442
        self.assertEqual(set([(('name', 'fin1'), 'data'),
 
443
            (('name', 'fin2'), 'beta')]),
 
444
            set(index.iter_entries_prefix([('name', None)])))
 
445
 
 
446
    def test_iter_key_prefix_2_key_element_refs(self):
 
447
        index = self.make_index(1, key_elements=2, nodes=[
 
448
            (('name', 'fin1'), 'data', ([('ref', 'erence')], )),
 
449
            (('name', 'fin2'), 'beta', ([], )),
 
450
            (('ref', 'erence'), 'refdata', ([], ))])
 
451
        self.assertEqual(set([(('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
452
            (('ref', 'erence'), 'refdata', ((), ))]),
 
453
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
 
454
        self.assertEqual(set([(('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
455
            (('name', 'fin2'), 'beta', ((), ))]),
 
456
            set(index.iter_entries_prefix([('name', None)])))
299
457
 
300
458
    def test_validate_bad_index_errors(self):
301
459
        trans = self.get_transport()
321
479
        self.assertRaises(errors.BadIndexData, index.validate)
322
480
 
323
481
    def test_validate_missing_end_line_nonempty(self):
324
 
        index = self.make_index(2, [('key', '', ([], []))])
 
482
        index = self.make_index(2, nodes=[(('key', ), '', ([], []))])
325
483
        trans = self.get_transport()
326
484
        content = trans.get_bytes('index')
327
485
        # truncate the last byte
333
491
        index.validate()
334
492
 
335
493
    def test_validate_no_refs_content(self):
336
 
        index = self.make_index(nodes=[('key', 'value', ())])
 
494
        index = self.make_index(nodes=[(('key', ), 'value', ())])
337
495
        index.validate()
338
496
 
339
497
 
340
498
class TestCombinedGraphIndex(TestCaseWithMemoryTransport):
341
499
 
342
 
    def make_index(self, name, ref_lists=0, nodes=[]):
343
 
        builder = GraphIndexBuilder(ref_lists)
 
500
    def make_index(self, name, ref_lists=0, key_elements=1, nodes=[]):
 
501
        builder = GraphIndexBuilder(ref_lists, key_elements=key_elements)
344
502
        for node, value, references in nodes:
345
503
            builder.add_node(node, value, references)
346
504
        stream = builder.finish()
355
513
 
356
514
    def test_add_index(self):
357
515
        index = CombinedGraphIndex([])
358
 
        index1 = self.make_index('name', 0, nodes=[('key', '', ())])
 
516
        index1 = self.make_index('name', 0, nodes=[(('key', ), '', ())])
359
517
        index.insert_index(0, index1)
360
 
        self.assertEqual([('key', '')], list(index.iter_all_entries()))
 
518
        self.assertEqual([(('key', ), '')], list(index.iter_all_entries()))
361
519
 
362
520
    def test_iter_all_entries_empty(self):
363
521
        index = CombinedGraphIndex([])
369
527
        self.assertEqual([], list(index.iter_all_entries()))
370
528
 
371
529
    def test_iter_all_entries_simple(self):
372
 
        index1 = self.make_index('name', nodes=[('name', 'data', ())])
 
530
        index1 = self.make_index('name', nodes=[(('name', ), 'data', ())])
373
531
        index = CombinedGraphIndex([index1])
374
 
        self.assertEqual([('name', 'data')],
 
532
        self.assertEqual([(('name', ), 'data')],
375
533
            list(index.iter_all_entries()))
376
534
 
377
535
    def test_iter_all_entries_two_indices(self):
378
 
        index1 = self.make_index('name1', nodes=[('name', 'data', ())])
379
 
        index2 = self.make_index('name2', nodes=[('2', '', ())])
 
536
        index1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
 
537
        index2 = self.make_index('name2', nodes=[(('2', ), '', ())])
380
538
        index = CombinedGraphIndex([index1, index2])
381
 
        self.assertEqual([('name', 'data'),
382
 
            ('2', '')],
 
539
        self.assertEqual([(('name', ), 'data'),
 
540
            (('2', ), '')],
383
541
            list(index.iter_all_entries()))
384
542
 
385
543
    def test_iter_entries_two_indices_dup_key(self):
386
 
        index1 = self.make_index('name1', nodes=[('name', 'data', ())])
387
 
        index2 = self.make_index('name2', nodes=[('name', 'data', ())])
 
544
        index1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
 
545
        index2 = self.make_index('name2', nodes=[(('name', ), 'data', ())])
388
546
        index = CombinedGraphIndex([index1, index2])
389
 
        self.assertEqual([('name', 'data')],
390
 
            list(index.iter_entries(['name'])))
 
547
        self.assertEqual([(('name', ), 'data')],
 
548
            list(index.iter_entries([('name', )])))
391
549
 
392
550
    def test_iter_all_entries_two_indices_dup_key(self):
393
 
        index1 = self.make_index('name1', nodes=[('name', 'data', ())])
394
 
        index2 = self.make_index('name2', nodes=[('name', 'data', ())])
 
551
        index1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
 
552
        index2 = self.make_index('name2', nodes=[(('name', ), 'data', ())])
395
553
        index = CombinedGraphIndex([index1, index2])
396
 
        self.assertEqual([('name', 'data')],
 
554
        self.assertEqual([(('name', ), 'data')],
397
555
            list(index.iter_all_entries()))
398
556
 
 
557
    def test_iter_key_prefix_2_key_element_refs(self):
 
558
        index1 = self.make_index('1', 1, key_elements=2, nodes=[
 
559
            (('name', 'fin1'), 'data', ([('ref', 'erence')], ))])
 
560
        index2 = self.make_index('2', 1, key_elements=2, nodes=[
 
561
            (('name', 'fin2'), 'beta', ([], )),
 
562
            (('ref', 'erence'), 'refdata', ([], ))])
 
563
        index = CombinedGraphIndex([index1, index2])
 
564
        self.assertEqual(set([(('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
565
            (('ref', 'erence'), 'refdata', ((), ))]),
 
566
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
 
567
        self.assertEqual(set([(('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
568
            (('name', 'fin2'), 'beta', ((), ))]),
 
569
            set(index.iter_entries_prefix([('name', None)])))
 
570
 
399
571
    def test_iter_nothing_empty(self):
400
572
        index = CombinedGraphIndex([])
401
573
        self.assertEqual([], list(index.iter_entries([])))
407
579
 
408
580
    def test_iter_all_keys(self):
409
581
        index1 = self.make_index('1', 1, nodes=[
410
 
            ('name', 'data', (['ref'], ))])
 
582
            (('name', ), 'data', ([('ref', )], ))])
411
583
        index2 = self.make_index('2', 1, nodes=[
412
 
            ('ref', 'refdata', ((), ))])
 
584
            (('ref', ), 'refdata', ((), ))])
413
585
        index = CombinedGraphIndex([index1, index2])
414
 
        self.assertEqual(set([('name', 'data', (('ref', ), )),
415
 
            ('ref', 'refdata', ((), ))]),
416
 
            set(index.iter_entries(['name', 'ref'])))
 
586
        self.assertEqual(set([(('name', ), 'data', ((('ref', ), ), )),
 
587
            (('ref', ), 'refdata', ((), ))]),
 
588
            set(index.iter_entries([('name', ), ('ref', )])))
417
589
 
418
590
    def test_iter_all_keys_dup_entry(self):
419
591
        index1 = self.make_index('1', 1, nodes=[
420
 
            ('name', 'data', (['ref'], )),
421
 
            ('ref', 'refdata', ([], ))])
 
592
            (('name', ), 'data', ([('ref', )], )),
 
593
            (('ref', ), 'refdata', ([], ))])
422
594
        index2 = self.make_index('2', 1, nodes=[
423
 
            ('ref', 'refdata', ([], ))])
 
595
            (('ref', ), 'refdata', ([], ))])
424
596
        index = CombinedGraphIndex([index1, index2])
425
 
        self.assertEqual(set([('name', 'data', (('ref',),)),
426
 
            ('ref', 'refdata', ((), ))]),
427
 
            set(index.iter_entries(['name', 'ref'])))
 
597
        self.assertEqual(set([(('name', ), 'data', ((('ref',),),)),
 
598
            (('ref', ), 'refdata', ((), ))]),
 
599
            set(index.iter_entries([('name', ), ('ref', )])))
428
600
 
429
601
    def test_iter_missing_entry_empty(self):
430
602
        index = CombinedGraphIndex([])
431
 
        self.assertEqual([], list(index.iter_entries(['a'])))
 
603
        self.assertEqual([], list(index.iter_entries([('a', )])))
432
604
 
433
605
    def test_iter_missing_entry_one_index(self):
434
606
        index1 = self.make_index('1')
435
607
        index = CombinedGraphIndex([index1])
436
 
        self.assertEqual([], list(index.iter_entries(['a'])))
 
608
        self.assertEqual([], list(index.iter_entries([('a', )])))
437
609
 
438
610
    def test_iter_missing_entry_two_index(self):
439
611
        index1 = self.make_index('1')
440
612
        index2 = self.make_index('2')
441
613
        index = CombinedGraphIndex([index1, index2])
442
 
        self.assertEqual([], list(index.iter_entries(['a'])))
 
614
        self.assertEqual([], list(index.iter_entries([('a', )])))
443
615
 
444
616
    def test_iter_entry_present_one_index_only(self):
445
 
        index1 = self.make_index('1', nodes=[('key', '', ())])
 
617
        index1 = self.make_index('1', nodes=[(('key', ), '', ())])
446
618
        index2 = self.make_index('2', nodes=[])
447
619
        index = CombinedGraphIndex([index1, index2])
448
 
        self.assertEqual([('key', '')],
449
 
            list(index.iter_entries(['key'])))
 
620
        self.assertEqual([(('key', ), '')],
 
621
            list(index.iter_entries([('key', )])))
450
622
        # and in the other direction
451
623
        index = CombinedGraphIndex([index2, index1])
452
 
        self.assertEqual([('key', '')],
453
 
            list(index.iter_entries(['key'])))
 
624
        self.assertEqual([(('key', ), '')],
 
625
            list(index.iter_entries([('key', )])))
454
626
 
455
627
    def test_validate_bad_child_index_errors(self):
456
628
        trans = self.get_transport()
466
638
 
467
639
class TestInMemoryGraphIndex(TestCaseWithMemoryTransport):
468
640
 
469
 
    def make_index(self, ref_lists=0, nodes=[]):
470
 
        result = InMemoryGraphIndex(ref_lists)
 
641
    def make_index(self, ref_lists=0, key_elements=1, nodes=[]):
 
642
        result = InMemoryGraphIndex(ref_lists, key_elements=key_elements)
471
643
        result.add_nodes(nodes)
472
644
        return result
473
645
 
 
646
    def test_add_nodes_no_refs(self):
 
647
        index = self.make_index(0)
 
648
        index.add_nodes([(('name', ), 'data')])
 
649
        index.add_nodes([(('name2', ), ''), (('name3', ), '')])
 
650
        self.assertEqual(set([
 
651
            (('name', ), 'data'),
 
652
            (('name2', ), ''),
 
653
            (('name3', ), ''),
 
654
            ]), set(index.iter_all_entries()))
 
655
 
474
656
    def test_add_nodes(self):
475
657
        index = self.make_index(1)
476
 
        index.add_nodes([('name', 'data', ([],))])
477
 
        index.add_nodes([('name2', '', ([],)), ('name3', '', (['r'],))])
 
658
        index.add_nodes([(('name', ), 'data', ([],))])
 
659
        index.add_nodes([(('name2', ), '', ([],)), (('name3', ), '', ([('r', )],))])
478
660
        self.assertEqual(set([
479
 
            ('name', 'data', ((),)),
480
 
            ('name2', '', ((),)),
481
 
            ('name3', '', (('r',),)),
 
661
            (('name', ), 'data', ((),)),
 
662
            (('name2', ), '', ((),)),
 
663
            (('name3', ), '', ((('r', ), ), )),
482
664
            ]), set(index.iter_all_entries()))
483
665
 
484
666
    def test_iter_all_entries_empty(self):
486
668
        self.assertEqual([], list(index.iter_all_entries()))
487
669
 
488
670
    def test_iter_all_entries_simple(self):
489
 
        index = self.make_index(nodes=[('name', 'data', ())])
490
 
        self.assertEqual([('name', 'data')],
 
671
        index = self.make_index(nodes=[(('name', ), 'data')])
 
672
        self.assertEqual([(('name', ), 'data')],
491
673
            list(index.iter_all_entries()))
492
674
 
493
675
    def test_iter_all_entries_references(self):
494
676
        index = self.make_index(1, nodes=[
495
 
            ('name', 'data', (['ref'], )),
496
 
            ('ref', 'refdata', ([], ))])
497
 
        self.assertEqual(set([('name', 'data', (('ref',),)),
498
 
            ('ref', 'refdata', ((), ))]),
 
677
            (('name', ), 'data', ([('ref', )], )),
 
678
            (('ref', ), 'refdata', ([], ))])
 
679
        self.assertEqual(set([(('name', ), 'data', ((('ref', ),),)),
 
680
            (('ref', ), 'refdata', ((), ))]),
499
681
            set(index.iter_all_entries()))
500
682
 
501
683
    def test_iteration_absent_skipped(self):
502
684
        index = self.make_index(1, nodes=[
503
 
            ('name', 'data', (['ref'], ))])
504
 
        self.assertEqual(set([('name', 'data', (('ref',),))]),
 
685
            (('name', ), 'data', ([('ref', )], ))])
 
686
        self.assertEqual(set([(('name', ), 'data', ((('ref',),),))]),
505
687
            set(index.iter_all_entries()))
506
 
        self.assertEqual(set([('name', 'data', (('ref',),))]),
507
 
            set(index.iter_entries(['name'])))
508
 
        self.assertEqual([], list(index.iter_entries(['ref'])))
 
688
        self.assertEqual(set([(('name', ), 'data', ((('ref',),),))]),
 
689
            set(index.iter_entries([('name', )])))
 
690
        self.assertEqual([], list(index.iter_entries([('ref', )])))
509
691
 
510
692
    def test_iter_all_keys(self):
511
693
        index = self.make_index(1, nodes=[
512
 
            ('name', 'data', (['ref'], )),
513
 
            ('ref', 'refdata', ([], ))])
514
 
        self.assertEqual(set([('name', 'data', (('ref',),)),
515
 
            ('ref', 'refdata', ((), ))]),
516
 
            set(index.iter_entries(['name', 'ref'])))
 
694
            (('name', ), 'data', ([('ref', )], )),
 
695
            (('ref', ), 'refdata', ([], ))])
 
696
        self.assertEqual(set([(('name', ), 'data', ((('ref',),),)),
 
697
            (('ref', ), 'refdata', ((), ))]),
 
698
            set(index.iter_entries([('name', ), ('ref', )])))
 
699
 
 
700
    def test_iter_key_prefix_1_key_element_no_refs(self):
 
701
        index = self.make_index( nodes=[
 
702
            (('name', ), 'data'),
 
703
            (('ref', ), 'refdata')])
 
704
        self.assertEqual(set([(('name', ), 'data'),
 
705
            (('ref', ), 'refdata')]),
 
706
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
 
707
 
 
708
    def test_iter_key_prefix_1_key_element_refs(self):
 
709
        index = self.make_index(1, nodes=[
 
710
            (('name', ), 'data', ([('ref', )], )),
 
711
            (('ref', ), 'refdata', ([], ))])
 
712
        self.assertEqual(set([(('name', ), 'data', ((('ref',),),)),
 
713
            (('ref', ), 'refdata', ((), ))]),
 
714
            set(index.iter_entries_prefix([('name', ), ('ref', )])))
 
715
 
 
716
    def test_iter_key_prefix_2_key_element_no_refs(self):
 
717
        index = self.make_index(key_elements=2, nodes=[
 
718
            (('name', 'fin1'), 'data'),
 
719
            (('name', 'fin2'), 'beta'),
 
720
            (('ref', 'erence'), 'refdata')])
 
721
        self.assertEqual(set([(('name', 'fin1'), 'data'),
 
722
            (('ref', 'erence'), 'refdata')]),
 
723
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
 
724
        self.assertEqual(set([(('name', 'fin1'), 'data'),
 
725
            (('name', 'fin2'), 'beta')]),
 
726
            set(index.iter_entries_prefix([('name', None)])))
 
727
 
 
728
    def test_iter_key_prefix_2_key_element_refs(self):
 
729
        index = self.make_index(1, key_elements=2, nodes=[
 
730
            (('name', 'fin1'), 'data', ([('ref', 'erence')], )),
 
731
            (('name', 'fin2'), 'beta', ([], )),
 
732
            (('ref', 'erence'), 'refdata', ([], ))])
 
733
        self.assertEqual(set([(('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
734
            (('ref', 'erence'), 'refdata', ((), ))]),
 
735
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
 
736
        self.assertEqual(set([(('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
 
737
            (('name', 'fin2'), 'beta', ((), ))]),
 
738
            set(index.iter_entries_prefix([('name', None)])))
517
739
 
518
740
    def test_iter_nothing_empty(self):
519
741
        index = self.make_index()
528
750
        index.validate()
529
751
 
530
752
    def test_validate_no_refs_content(self):
531
 
        index = self.make_index(nodes=[('key', 'value', ())])
 
753
        index = self.make_index(nodes=[(('key', ), 'value')])
532
754
        index.validate()
533
755
 
534
756