/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2592.1.4 by Robert Collins
Create a GraphIndexBuilder.
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
2592.1.5 by Robert Collins
Trivial index reading.
19
from bzrlib import errors
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
20
from bzrlib.index import *
2592.1.4 by Robert Collins
Create a GraphIndexBuilder.
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()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
30
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\n\n", contents)
2592.1.6 by Robert Collins
Record the number of node reference lists a particular index has.
31
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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)
37
2592.1.6 by Robert Collins
Record the number of node reference lists a particular index has.
38
    def test_build_index_one_reference_list_empty(self):
39
        builder = GraphIndexBuilder(reference_lists=1)
40
        stream = builder.finish()
41
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
42
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n\n", contents)
2592.1.4 by Robert Collins
Create a GraphIndexBuilder.
43
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
44
    def test_build_index_two_reference_list_empty(self):
45
        builder = GraphIndexBuilder(reference_lists=2)
46
        stream = builder.finish()
47
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
48
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\n\n", contents)
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
49
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
50
    def test_build_index_one_node_no_refs(self):
51
        builder = GraphIndexBuilder()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
52
        builder.add_node(('akey', ), 'data')
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
53
        stream = builder.finish()
54
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
55
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\n"
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
56
            "akey\x00\x00\x00data\n\n", contents)
57
58
    def test_build_index_one_node_no_refs_accepts_empty_reflist(self):
59
        builder = GraphIndexBuilder()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
60
        builder.add_node(('akey', ), 'data', ())
2592.1.12 by Robert Collins
Handle basic node adds.
61
        stream = builder.finish()
62
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
63
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
64
            "akey\x00\x00\x00data\n\n", contents)
2592.1.12 by Robert Collins
Handle basic node adds.
65
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
66
    def test_build_index_one_node_2_element_keys(self):
2624.2.11 by Robert Collins
Review comments.
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.
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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
2592.1.21 by Robert Collins
Empty values are ok.
77
    def test_add_node_empty_value(self):
78
        builder = GraphIndexBuilder()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
79
        builder.add_node(('akey', ), '')
2592.1.21 by Robert Collins
Empty values are ok.
80
        stream = builder.finish()
81
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
82
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
83
            "akey\x00\x00\x00\n\n", contents)
2592.1.21 by Robert Collins
Empty values are ok.
84
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
85
    def test_build_index_nodes_sorted(self):
2592.1.17 by Robert Collins
Multi node sort order is defined.
86
        # the highest sorted node comes first.
87
        builder = GraphIndexBuilder()
88
        # use three to have a good chance of glitching dictionary hash
89
        # lookups etc. Insert in randomish order that is not correct
90
        # and not the reverse of the correct order.
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
91
        builder.add_node(('2002', ), 'data')
92
        builder.add_node(('2000', ), 'data')
93
        builder.add_node(('2001', ), 'data')
2592.1.17 by Robert Collins
Multi node sort order is defined.
94
        stream = builder.finish()
95
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
96
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=0\nkey_elements=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
97
            "2000\x00\x00\x00data\n"
98
            "2001\x00\x00\x00data\n"
99
            "2002\x00\x00\x00data\n"
2592.1.17 by Robert Collins
Multi node sort order is defined.
100
            "\n", contents)
101
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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
2592.1.19 by Robert Collins
Node references are tab separated.
131
    def test_build_index_reference_lists_are_included_one(self):
132
        builder = GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
133
        builder.add_node(('key', ), 'data', ([], ))
2592.1.19 by Robert Collins
Node references are tab separated.
134
        stream = builder.finish()
135
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
136
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
137
            "key\x00\x00\x00data\n"
2592.1.19 by Robert Collins
Node references are tab separated.
138
            "\n", contents)
139
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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
2592.1.19 by Robert Collins
Node references are tab separated.
149
    def test_build_index_reference_lists_are_included_two(self):
150
        builder = GraphIndexBuilder(reference_lists=2)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
151
        builder.add_node(('key', ), 'data', ([], []))
2592.1.19 by Robert Collins
Node references are tab separated.
152
        stream = builder.finish()
153
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
154
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
155
            "key\x00\x00\t\x00data\n"
2592.1.19 by Robert Collins
Node references are tab separated.
156
            "\n", contents)
157
2592.1.22 by Robert Collins
Node references are byte offsets.
158
    def test_node_references_are_byte_offsets(self):
159
        builder = GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
160
        builder.add_node(('reference', ), 'data', ([], ))
161
        builder.add_node(('key', ), 'data', ([('reference', )], ))
2592.1.22 by Robert Collins
Node references are byte offsets.
162
        stream = builder.finish()
163
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
164
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n"
165
            "key\x00\x0066\x00data\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
166
            "reference\x00\x00\x00data\n"
2592.1.22 by Robert Collins
Node references are byte offsets.
167
            "\n", contents)
168
2592.1.23 by Robert Collins
node reference delimiting tested.
169
    def test_node_references_are_cr_delimited(self):
170
        builder = GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
171
        builder.add_node(('reference', ), 'data', ([], ))
172
        builder.add_node(('reference2', ), 'data', ([], ))
173
        builder.add_node(('key', ), 'data', ([('reference', ), ('reference2', )], ))
2592.1.23 by Robert Collins
node reference delimiting tested.
174
        stream = builder.finish()
175
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
176
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n"
177
            "key\x00\x00071\r088\x00data\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
178
            "reference\x00\x00\x00data\n"
179
            "reference2\x00\x00\x00data\n"
2592.1.23 by Robert Collins
node reference delimiting tested.
180
            "\n", contents)
181
2592.1.24 by Robert Collins
Delimiting of multiple reference lists is by \t
182
    def test_multiple_reference_lists_are_tab_delimited(self):
183
        builder = GraphIndexBuilder(reference_lists=2)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
184
        builder.add_node(('keference', ), 'data', ([], []))
185
        builder.add_node(('rey', ), 'data', ([('keference', )], [('keference', )]))
2592.1.24 by Robert Collins
Delimiting of multiple reference lists is by \t
186
        stream = builder.finish()
187
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
188
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
189
            "keference\x00\x00\t\x00data\n"
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
190
            "rey\x00\x0053\t53\x00data\n"
2592.1.24 by Robert Collins
Delimiting of multiple reference lists is by \t
191
            "\n", contents)
192
2592.1.25 by Robert Collins
Fix and tune node offset calculation.
193
    def test_add_node_referencing_missing_key_makes_absent(self):
194
        builder = GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
195
        builder.add_node(('rey', ), 'data', ([('beference', ), ('aeference2', )], ))
2592.1.25 by Robert Collins
Fix and tune node offset calculation.
196
        stream = builder.finish()
197
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
198
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n"
2592.1.43 by Robert Collins
Various index tweaks and test clarity from John's review.
199
            "aeference2\x00a\x00\x00\n"
200
            "beference\x00a\x00\x00\n"
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
201
            "rey\x00\x0068\r53\x00data\n"
2592.1.25 by Robert Collins
Fix and tune node offset calculation.
202
            "\n", contents)
203
2592.1.26 by Robert Collins
Test digit buffering is accurate.
204
    def test_node_references_three_digits(self):
205
        # test the node digit expands as needed.
206
        builder = GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
207
        references = [(str(val), ) for val in reversed(range(9))]
208
        builder.add_node(('2-key', ), '', (references, ))
2592.1.26 by Robert Collins
Test digit buffering is accurate.
209
        stream = builder.finish()
210
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
211
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=1\nkey_elements=1\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
212
            "0\x00a\x00\x00\n"
213
            "1\x00a\x00\x00\n"
214
            "2\x00a\x00\x00\n"
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
215
            "2-key\x00\x00145\r139\r133\r127\r121\r115\r065\r059\r053\x00\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
216
            "3\x00a\x00\x00\n"
217
            "4\x00a\x00\x00\n"
218
            "5\x00a\x00\x00\n"
219
            "6\x00a\x00\x00\n"
220
            "7\x00a\x00\x00\n"
2592.1.26 by Robert Collins
Test digit buffering is accurate.
221
            "8\x00a\x00\x00\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
222
            "\n", contents)
223
224
    def test_absent_has_no_reference_overhead(self):
225
        # the offsets after an absent record should be correct when there are
226
        # >1 reference lists.
227
        builder = GraphIndexBuilder(reference_lists=2)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
228
        builder.add_node(('parent', ), '', ([('aail', ), ('zther', )], []))
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
229
        stream = builder.finish()
230
        contents = stream.read()
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
231
        self.assertEqual("Bazaar Graph Index 1\nnode_ref_lists=2\nkey_elements=1\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
232
            "aail\x00a\x00\x00\n"
2624.2.8 by Robert Collins
Explicitly mark the number of keys elements in use in GraphIndex files.
233
            "parent\x00\x0053\r78\t\x00\n"
2592.1.40 by Robert Collins
Reverse index ordering - we do not have date prefixed revids.
234
            "zther\x00a\x00\x00\n"
2592.1.26 by Robert Collins
Test digit buffering is accurate.
235
            "\n", contents)
236
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
237
    def test_add_node_bad_key(self):
2592.1.12 by Robert Collins
Handle basic node adds.
238
        builder = GraphIndexBuilder()
2592.1.14 by Robert Collins
Detect bad reference key values.
239
        for bad_char in '\t\n\x0b\x0c\r\x00 ':
240
            self.assertRaises(errors.BadIndexKey, builder.add_node,
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
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')
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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')
2592.1.12 by Robert Collins
Handle basic node adds.
257
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
258
    def test_add_node_bad_data(self):
2592.1.12 by Robert Collins
Handle basic node adds.
259
        builder = GraphIndexBuilder()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
260
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
261
            'data\naa')
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
262
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
263
            'data\x00aa')
2592.1.12 by Robert Collins
Handle basic node adds.
264
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
265
    def test_add_node_bad_mismatched_ref_lists_length(self):
266
        builder = GraphIndexBuilder()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
267
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
268
            'data aa', ([], ))
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
269
        builder = GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
270
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
271
            'data aa')
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
272
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
273
            'data aa', (), )
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
274
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
275
            'data aa', ([], []))
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
276
        builder = GraphIndexBuilder(reference_lists=2)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
277
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
278
            'data aa')
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
279
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
280
            'data aa', ([], ))
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
281
        self.assertRaises(errors.BadIndexValue, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
282
            'data aa', ([], [], []))
2592.1.13 by Robert Collins
Handle mismatched numbers of reference lists.
283
2592.1.14 by Robert Collins
Detect bad reference key values.
284
    def test_add_node_bad_key_in_reference_lists(self):
285
        # first list, first key - trivial
286
        builder = GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
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')], ))
2592.1.14 by Robert Collins
Detect bad reference key values.
298
        # need to check more than the first key in the list
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
299
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
300
            'data aa', ([('agoodkey', ), ('that is a bad key', )], ))
2592.1.14 by Robert Collins
Detect bad reference key values.
301
        # and if there is more than one list it should be getting checked
302
        # too
303
        builder = GraphIndexBuilder(reference_lists=2)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
304
        self.assertRaises(errors.BadIndexKey, builder.add_node, ('akey', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
305
            'data aa', ([], ['a bad key']))
2592.1.14 by Robert Collins
Detect bad reference key values.
306
2592.1.15 by Robert Collins
Detect duplicate key insertion.
307
    def test_add_duplicate_key(self):
308
        builder = GraphIndexBuilder()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
309
        builder.add_node(('key', ), 'data')
310
        self.assertRaises(errors.BadIndexDuplicateKey, builder.add_node, ('key', ),
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
311
            'data')
2592.1.15 by Robert Collins
Detect duplicate key insertion.
312
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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
2592.1.16 by Robert Collins
Can add keys after referencing them.
319
    def test_add_key_after_referencing_key(self):
320
        builder = GraphIndexBuilder(reference_lists=1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
321
        builder.add_node(('key', ), 'data', ([('reference', )], ))
322
        builder.add_node(('reference', ), 'data', ([],))
2592.1.16 by Robert Collins
Can add keys after referencing them.
323
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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', ([],))
328
2592.1.5 by Robert Collins
Trivial index reading.
329
330
class TestGraphIndex(TestCaseWithMemoryTransport):
331
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
332
    def make_index(self, ref_lists=0, key_elements=1, nodes=[]):
333
        builder = GraphIndexBuilder(ref_lists, key_elements=key_elements)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
334
        for node, value, references in nodes:
335
            builder.add_node(node, value, references)
2592.1.5 by Robert Collins
Trivial index reading.
336
        stream = builder.finish()
337
        trans = self.get_transport()
2592.1.6 by Robert Collins
Record the number of node reference lists a particular index has.
338
        trans.put_file('index', stream)
2592.1.5 by Robert Collins
Trivial index reading.
339
        return GraphIndex(trans, 'index')
340
2592.1.7 by Robert Collins
A validate that goes boom.
341
    def test_open_bad_index_no_error(self):
342
        trans = self.get_transport()
343
        trans.put_bytes('name', "not an index\n")
344
        index = GraphIndex(trans, 'name')
345
2592.1.5 by Robert Collins
Trivial index reading.
346
    def test_iter_all_entries_empty(self):
347
        index = self.make_index()
348
        self.assertEqual([], list(index.iter_all_entries()))
349
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
350
    def test_iter_all_entries_simple(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
351
        index = self.make_index(nodes=[(('name', ), 'data', ())])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
352
        self.assertEqual([(index, ('name', ), 'data')],
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
353
            list(index.iter_all_entries()))
354
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
355
    def test_iter_all_entries_simple_2_elements(self):
356
        index = self.make_index(key_elements=2,
357
            nodes=[(('name', 'surname'), 'data', ())])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
358
        self.assertEqual([(index, ('name', 'surname'), 'data')],
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
359
            list(index.iter_all_entries()))
360
2592.1.28 by Robert Collins
Basic two pass iter_all_entries.
361
    def test_iter_all_entries_references_resolved(self):
362
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
363
            (('name', ), 'data', ([('ref', )], )),
364
            (('ref', ), 'refdata', ([], ))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
365
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),)),
366
            (index, ('ref', ), 'refdata', ((), ))]),
2592.1.28 by Robert Collins
Basic two pass iter_all_entries.
367
            set(index.iter_all_entries()))
368
2592.1.30 by Robert Collins
Absent entries are not yeilded.
369
    def test_iteration_absent_skipped(self):
370
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
371
            (('name', ), 'data', ([('ref', )], ))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
372
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),))]),
2592.1.30 by Robert Collins
Absent entries are not yeilded.
373
            set(index.iter_all_entries()))
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
374
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),))]),
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
375
            set(index.iter_entries([('name', )])))
376
        self.assertEqual([], list(index.iter_entries([('ref', )])))
2592.1.30 by Robert Collins
Absent entries are not yeilded.
377
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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')], ))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
381
        self.assertEqual(set([(index, ('name', 'fin'), 'data', ((('ref', 'erence'),),))]),
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
382
            set(index.iter_all_entries()))
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
383
        self.assertEqual(set([(index, ('name', 'fin'), 'data', ((('ref', 'erence'),),))]),
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
384
            set(index.iter_entries([('name', 'fin')])))
385
        self.assertEqual([], list(index.iter_entries([('ref', 'erence')])))
386
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
387
    def test_iter_all_keys(self):
2592.1.29 by Robert Collins
Basic iter_entries working.
388
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
389
            (('name', ), 'data', ([('ref', )], )),
390
            (('ref', ), 'refdata', ([], ))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
391
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),)),
392
            (index, ('ref', ), 'refdata', ((), ))]),
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
393
            set(index.iter_entries([('name', ), ('ref', )])))
2592.1.29 by Robert Collins
Basic iter_entries working.
394
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
395
    def test_iter_nothing_empty(self):
2592.1.9 by Robert Collins
Iterating no keys should work too.
396
        index = self.make_index()
397
        self.assertEqual([], list(index.iter_entries([])))
398
2592.1.5 by Robert Collins
Trivial index reading.
399
    def test_iter_missing_entry_empty(self):
400
        index = self.make_index()
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
401
        self.assertEqual([], list(index.iter_entries([('a', )])))
2592.1.7 by Robert Collins
A validate that goes boom.
402
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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', ())])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
422
        self.assertEqual(set([(index, ('name', ), 'data'),
423
            (index, ('ref', ), 'refdata')]),
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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', ([], ))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
430
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),)),
431
            (index, ('ref', ), 'refdata', ((), ))]),
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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', ())])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
439
        self.assertEqual(set([(index, ('name', 'fin1'), 'data'),
440
            (index, ('ref', 'erence'), 'refdata')]),
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
441
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
442
        self.assertEqual(set([(index, ('name', 'fin1'), 'data'),
443
            (index, ('name', 'fin2'), 'beta')]),
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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', ([], ))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
451
        self.assertEqual(set([(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
452
            (index, ('ref', 'erence'), 'refdata', ((), ))]),
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
453
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
454
        self.assertEqual(set([(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
455
            (index, ('name', 'fin2'), 'beta', ((), ))]),
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
456
            set(index.iter_entries_prefix([('name', None)])))
457
2592.1.7 by Robert Collins
A validate that goes boom.
458
    def test_validate_bad_index_errors(self):
459
        trans = self.get_transport()
460
        trans.put_bytes('name', "not an index\n")
461
        index = GraphIndex(trans, 'name')
462
        self.assertRaises(errors.BadIndexFormatSignature, index.validate)
2592.1.8 by Robert Collins
Empty files should validate ok.
463
2592.1.10 by Robert Collins
Make validate detect node reference parsing errors.
464
    def test_validate_bad_node_refs(self):
465
        index = self.make_index(2)
466
        trans = self.get_transport()
467
        content = trans.get_bytes('index')
468
        # change the options line to end with a rather than a parseable number
469
        new_content = content[:-2] + 'a\n\n'
470
        trans.put_bytes('index', new_content)
471
        self.assertRaises(errors.BadIndexOptions, index.validate)
472
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
473
    def test_validate_missing_end_line_empty(self):
2592.1.11 by Robert Collins
Detect truncated indices.
474
        index = self.make_index(2)
475
        trans = self.get_transport()
476
        content = trans.get_bytes('index')
477
        # truncate the last byte
478
        trans.put_bytes('index', content[:-1])
479
        self.assertRaises(errors.BadIndexData, index.validate)
480
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
481
    def test_validate_missing_end_line_nonempty(self):
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
482
        index = self.make_index(2, nodes=[(('key', ), '', ([], []))])
2592.1.27 by Robert Collins
Test missing end lines with non-empty indices.
483
        trans = self.get_transport()
484
        content = trans.get_bytes('index')
485
        # truncate the last byte
486
        trans.put_bytes('index', content[:-1])
487
        self.assertRaises(errors.BadIndexData, index.validate)
488
2592.1.8 by Robert Collins
Empty files should validate ok.
489
    def test_validate_empty(self):
490
        index = self.make_index()
491
        index.validate()
2592.1.12 by Robert Collins
Handle basic node adds.
492
493
    def test_validate_no_refs_content(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
494
        index = self.make_index(nodes=[(('key', ), 'value', ())])
2592.1.12 by Robert Collins
Handle basic node adds.
495
        index.validate()
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
496
497
498
class TestCombinedGraphIndex(TestCaseWithMemoryTransport):
499
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
500
    def make_index(self, name, ref_lists=0, key_elements=1, nodes=[]):
501
        builder = GraphIndexBuilder(ref_lists, key_elements=key_elements)
2592.1.46 by Robert Collins
Make GraphIndex accept nodes as key, value, references, so that the method
502
        for node, value, references in nodes:
503
            builder.add_node(node, value, references)
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
504
        stream = builder.finish()
505
        trans = self.get_transport()
506
        trans.put_file(name, stream)
507
        return GraphIndex(trans, name)
508
509
    def test_open_missing_index_no_error(self):
510
        trans = self.get_transport()
511
        index1 = GraphIndex(trans, 'missing')
512
        index = CombinedGraphIndex([index1])
513
2592.1.37 by Robert Collins
Add CombinedGraphIndex.insert_index.
514
    def test_add_index(self):
515
        index = CombinedGraphIndex([])
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
516
        index1 = self.make_index('name', 0, nodes=[(('key', ), '', ())])
2592.1.37 by Robert Collins
Add CombinedGraphIndex.insert_index.
517
        index.insert_index(0, index1)
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
518
        self.assertEqual([(index1, ('key', ), '')], list(index.iter_all_entries()))
2592.1.37 by Robert Collins
Add CombinedGraphIndex.insert_index.
519
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
520
    def test_iter_all_entries_empty(self):
521
        index = CombinedGraphIndex([])
522
        self.assertEqual([], list(index.iter_all_entries()))
523
524
    def test_iter_all_entries_children_empty(self):
525
        index1 = self.make_index('name')
526
        index = CombinedGraphIndex([index1])
527
        self.assertEqual([], list(index.iter_all_entries()))
528
529
    def test_iter_all_entries_simple(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
530
        index1 = self.make_index('name', nodes=[(('name', ), 'data', ())])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
531
        index = CombinedGraphIndex([index1])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
532
        self.assertEqual([(index1, ('name', ), 'data')],
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
533
            list(index.iter_all_entries()))
534
535
    def test_iter_all_entries_two_indices(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
536
        index1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
537
        index2 = self.make_index('name2', nodes=[(('2', ), '', ())])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
538
        index = CombinedGraphIndex([index1, index2])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
539
        self.assertEqual([(index1, ('name', ), 'data'),
540
            (index2, ('2', ), '')],
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
541
            list(index.iter_all_entries()))
542
2592.1.39 by Robert Collins
CombinedGraphIndex.iter_entries does not need to see all entries.
543
    def test_iter_entries_two_indices_dup_key(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
544
        index1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
545
        index2 = self.make_index('name2', nodes=[(('name', ), 'data', ())])
2592.1.39 by Robert Collins
CombinedGraphIndex.iter_entries does not need to see all entries.
546
        index = CombinedGraphIndex([index1, index2])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
547
        self.assertEqual([(index1, ('name', ), 'data')],
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
548
            list(index.iter_entries([('name', )])))
2592.1.39 by Robert Collins
CombinedGraphIndex.iter_entries does not need to see all entries.
549
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
550
    def test_iter_all_entries_two_indices_dup_key(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
551
        index1 = self.make_index('name1', nodes=[(('name', ), 'data', ())])
552
        index2 = self.make_index('name2', nodes=[(('name', ), 'data', ())])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
553
        index = CombinedGraphIndex([index1, index2])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
554
        self.assertEqual([(index1, ('name', ), 'data')],
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
555
            list(index.iter_all_entries()))
556
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
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])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
564
        self.assertEqual(set([(index1, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
565
            (index2, ('ref', 'erence'), 'refdata', ((), ))]),
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
566
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
567
        self.assertEqual(set([(index1, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
568
            (index2, ('name', 'fin2'), 'beta', ((), ))]),
2624.2.9 by Robert Collins
Introduce multiple component keys, which is what is needed to combine multiple knit indices into one.
569
            set(index.iter_entries_prefix([('name', None)])))
570
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
571
    def test_iter_nothing_empty(self):
572
        index = CombinedGraphIndex([])
573
        self.assertEqual([], list(index.iter_entries([])))
574
575
    def test_iter_nothing_children_empty(self):
576
        index1 = self.make_index('name')
577
        index = CombinedGraphIndex([index1])
578
        self.assertEqual([], list(index.iter_entries([])))
579
580
    def test_iter_all_keys(self):
581
        index1 = self.make_index('1', 1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
582
            (('name', ), 'data', ([('ref', )], ))])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
583
        index2 = self.make_index('2', 1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
584
            (('ref', ), 'refdata', ((), ))])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
585
        index = CombinedGraphIndex([index1, index2])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
586
        self.assertEqual(set([(index1, ('name', ), 'data', ((('ref', ), ), )),
587
            (index2, ('ref', ), 'refdata', ((), ))]),
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
588
            set(index.iter_entries([('name', ), ('ref', )])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
589
 
590
    def test_iter_all_keys_dup_entry(self):
591
        index1 = self.make_index('1', 1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
592
            (('name', ), 'data', ([('ref', )], )),
593
            (('ref', ), 'refdata', ([], ))])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
594
        index2 = self.make_index('2', 1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
595
            (('ref', ), 'refdata', ([], ))])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
596
        index = CombinedGraphIndex([index1, index2])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
597
        self.assertEqual(set([(index1, ('name', ), 'data', ((('ref',),),)),
598
            (index1, ('ref', ), 'refdata', ((), ))]),
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
599
            set(index.iter_entries([('name', ), ('ref', )])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
600
 
601
    def test_iter_missing_entry_empty(self):
602
        index = CombinedGraphIndex([])
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
603
        self.assertEqual([], list(index.iter_entries([('a', )])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
604
605
    def test_iter_missing_entry_one_index(self):
606
        index1 = self.make_index('1')
607
        index = CombinedGraphIndex([index1])
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
608
        self.assertEqual([], list(index.iter_entries([('a', )])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
609
610
    def test_iter_missing_entry_two_index(self):
611
        index1 = self.make_index('1')
612
        index2 = self.make_index('2')
613
        index = CombinedGraphIndex([index1, index2])
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
614
        self.assertEqual([], list(index.iter_entries([('a', )])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
615
 
616
    def test_iter_entry_present_one_index_only(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
617
        index1 = self.make_index('1', nodes=[(('key', ), '', ())])
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
618
        index2 = self.make_index('2', nodes=[])
619
        index = CombinedGraphIndex([index1, index2])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
620
        self.assertEqual([(index1, ('key', ), '')],
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
621
            list(index.iter_entries([('key', )])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
622
        # and in the other direction
623
        index = CombinedGraphIndex([index2, index1])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
624
        self.assertEqual([(index1, ('key', ), '')],
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
625
            list(index.iter_entries([('key', )])))
2592.1.31 by Robert Collins
Build a combined graph index to use multiple indices at once.
626
627
    def test_validate_bad_child_index_errors(self):
628
        trans = self.get_transport()
629
        trans.put_bytes('name', "not an index\n")
630
        index1 = GraphIndex(trans, 'name')
631
        index = CombinedGraphIndex([index1])
632
        self.assertRaises(errors.BadIndexFormatSignature, index.validate)
633
634
    def test_validate_empty(self):
635
        index = CombinedGraphIndex([])
636
        index.validate()
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
637
638
639
class TestInMemoryGraphIndex(TestCaseWithMemoryTransport):
640
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
641
    def make_index(self, ref_lists=0, key_elements=1, nodes=[]):
642
        result = InMemoryGraphIndex(ref_lists, key_elements=key_elements)
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
643
        result.add_nodes(nodes)
644
        return result
645
2624.2.1 by Robert Collins
InMemoryGraphIndex.add_nodes was inconsistent with other metods for non-node-reference indices.
646
    def test_add_nodes_no_refs(self):
647
        index = self.make_index(0)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
648
        index.add_nodes([(('name', ), 'data')])
649
        index.add_nodes([(('name2', ), ''), (('name3', ), '')])
2624.2.1 by Robert Collins
InMemoryGraphIndex.add_nodes was inconsistent with other metods for non-node-reference indices.
650
        self.assertEqual(set([
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
651
            (index, ('name', ), 'data'),
652
            (index, ('name2', ), ''),
653
            (index, ('name3', ), ''),
2624.2.1 by Robert Collins
InMemoryGraphIndex.add_nodes was inconsistent with other metods for non-node-reference indices.
654
            ]), set(index.iter_all_entries()))
655
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
656
    def test_add_nodes(self):
657
        index = self.make_index(1)
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
658
        index.add_nodes([(('name', ), 'data', ([],))])
659
        index.add_nodes([(('name2', ), '', ([],)), (('name3', ), '', ([('r', )],))])
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
660
        self.assertEqual(set([
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
661
            (index, ('name', ), 'data', ((),)),
662
            (index, ('name2', ), '', ((),)),
663
            (index, ('name3', ), '', ((('r', ), ), )),
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
664
            ]), set(index.iter_all_entries()))
665
666
    def test_iter_all_entries_empty(self):
667
        index = self.make_index()
668
        self.assertEqual([], list(index.iter_all_entries()))
669
670
    def test_iter_all_entries_simple(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
671
        index = self.make_index(nodes=[(('name', ), 'data')])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
672
        self.assertEqual([(index, ('name', ), 'data')],
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
673
            list(index.iter_all_entries()))
674
675
    def test_iter_all_entries_references(self):
676
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
677
            (('name', ), 'data', ([('ref', )], )),
678
            (('ref', ), 'refdata', ([], ))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
679
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref', ),),)),
680
            (index, ('ref', ), 'refdata', ((), ))]),
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
681
            set(index.iter_all_entries()))
682
683
    def test_iteration_absent_skipped(self):
684
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
685
            (('name', ), 'data', ([('ref', )], ))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
686
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),))]),
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
687
            set(index.iter_all_entries()))
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
688
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),))]),
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
689
            set(index.iter_entries([('name', )])))
690
        self.assertEqual([], list(index.iter_entries([('ref', )])))
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
691
692
    def test_iter_all_keys(self):
693
        index = self.make_index(1, nodes=[
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
694
            (('name', ), 'data', ([('ref', )], )),
695
            (('ref', ), 'refdata', ([], ))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
696
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),)),
697
            (index, ('ref', ), 'refdata', ((), ))]),
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
698
            set(index.iter_entries([('name', ), ('ref', )])))
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
699
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
700
    def test_iter_key_prefix_1_key_element_no_refs(self):
701
        index = self.make_index( nodes=[
702
            (('name', ), 'data'),
703
            (('ref', ), 'refdata')])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
704
        self.assertEqual(set([(index, ('name', ), 'data'),
705
            (index, ('ref', ), 'refdata')]),
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
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', ([], ))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
712
        self.assertEqual(set([(index, ('name', ), 'data', ((('ref',),),)),
713
            (index, ('ref', ), 'refdata', ((), ))]),
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
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')])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
721
        self.assertEqual(set([(index, ('name', 'fin1'), 'data'),
722
            (index, ('ref', 'erence'), 'refdata')]),
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
723
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
724
        self.assertEqual(set([(index, ('name', 'fin1'), 'data'),
725
            (index, ('name', 'fin2'), 'beta')]),
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
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', ([], ))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
733
        self.assertEqual(set([(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
734
            (index, ('ref', 'erence'), 'refdata', ((), ))]),
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
735
            set(index.iter_entries_prefix([('name', 'fin1'), ('ref', 'erence')])))
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
736
        self.assertEqual(set([(index, ('name', 'fin1'), 'data', ((('ref', 'erence'),),)),
737
            (index, ('name', 'fin2'), 'beta', ((), ))]),
2624.2.10 by Robert Collins
Also add iter_key_prefix support to InMemoryGraphIndex.
738
            set(index.iter_entries_prefix([('name', None)])))
739
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
740
    def test_iter_nothing_empty(self):
741
        index = self.make_index()
742
        self.assertEqual([], list(index.iter_entries([])))
743
744
    def test_iter_missing_entry_empty(self):
745
        index = self.make_index()
746
        self.assertEqual([], list(index.iter_entries(['a'])))
747
748
    def test_validate_empty(self):
749
        index = self.make_index()
750
        index.validate()
751
752
    def test_validate_no_refs_content(self):
2624.2.5 by Robert Collins
Change bzrlib.index.Index keys to be 1-tuples, not strings.
753
        index = self.make_index(nodes=[(('key', ), 'value')])
2592.1.38 by Robert Collins
Create an InMemoryGraphIndex for temporary indexing.
754
        index.validate()
755
756
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
757
class TestGraphIndexPrefixAdapter(TestCaseWithMemoryTransport):
758
2624.2.13 by Robert Collins
Implement add_node/add_nodes to the GraphIndexPrefixAdapter.
759
    def make_index(self, ref_lists=1, key_elements=2, nodes=[], add_callback=False):
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
760
        result = InMemoryGraphIndex(ref_lists, key_elements=key_elements)
761
        result.add_nodes(nodes)
2624.2.13 by Robert Collins
Implement add_node/add_nodes to the GraphIndexPrefixAdapter.
762
        if add_callback:
763
            add_nodes_callback=result.add_nodes
764
        else:
765
            add_nodes_callback=None
766
        adapter = GraphIndexPrefixAdapter(result, ('prefix', ), key_elements - 1,
767
            add_nodes_callback=add_nodes_callback)
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
768
        return result, adapter
769
2624.2.13 by Robert Collins
Implement add_node/add_nodes to the GraphIndexPrefixAdapter.
770
    def test_add_node(self):
771
        index, adapter = self.make_index(add_callback=True)
772
        adapter.add_node(('key',), 'value', ((('ref',),),))
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
773
        self.assertEqual(set([(index, ('prefix', 'key'), 'value', ((('prefix', 'ref'),),))]),
2624.2.13 by Robert Collins
Implement add_node/add_nodes to the GraphIndexPrefixAdapter.
774
            set(index.iter_all_entries()))
775
776
    def test_add_nodes(self):
777
        index, adapter = self.make_index(add_callback=True)
778
        adapter.add_nodes((
779
            (('key',), 'value', ((('ref',),),)),
780
            (('key2',), 'value2', ((),)),
781
            ))
782
        self.assertEqual(set([
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
783
            (index, ('prefix', 'key2'), 'value2', ((),)),
784
            (index, ('prefix', 'key'), 'value', ((('prefix', 'ref'),),))
2624.2.13 by Robert Collins
Implement add_node/add_nodes to the GraphIndexPrefixAdapter.
785
            ]),
786
            set(index.iter_all_entries()))
787
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
788
    def test_construct(self):
789
        index = InMemoryGraphIndex()
790
        adapter = GraphIndexPrefixAdapter(index, ('prefix', ), 1)
791
792
    def test_construct_with_callback(self):
793
        index = InMemoryGraphIndex()
794
        adapter = GraphIndexPrefixAdapter(index, ('prefix', ), 1, index.add_nodes)
795
796
    def test_iter_all_entries_cross_prefix_map_errors(self):
797
        index, adapter = self.make_index(nodes=[
798
            (('prefix', 'key1'), 'data1', ((('prefixaltered', 'key2'),),))])
799
        self.assertRaises(errors.BadIndexData, list, adapter.iter_all_entries())
800
801
    def test_iter_all_entries(self):
802
        index, adapter = self.make_index(nodes=[
803
            (('notprefix', 'key1'), 'data', ((), )),
804
            (('prefix', 'key1'), 'data1', ((), )),
805
            (('prefix', 'key2'), 'data2', ((('prefix', 'key1'),),))])
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
806
        self.assertEqual(set([(index, ('key1', ), 'data1', ((),)),
807
            (index, ('key2', ), 'data2', ((('key1',),),))]),
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
808
            set(adapter.iter_all_entries()))
809
810
    def test_iter_entries(self):
811
        index, adapter = self.make_index(nodes=[
812
            (('notprefix', 'key1'), 'data', ((), )),
813
            (('prefix', 'key1'), 'data1', ((), )),
814
            (('prefix', 'key2'), 'data2', ((('prefix', 'key1'),),))])
815
        # ask for many - get all
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
816
        self.assertEqual(set([(index, ('key1', ), 'data1', ((),)),
817
            (index, ('key2', ), 'data2', ((('key1', ),),))]),
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
818
            set(adapter.iter_entries([('key1', ), ('key2', )])))
819
        # ask for one, get one
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
820
        self.assertEqual(set([(index, ('key1', ), 'data1', ((),))]),
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
821
            set(adapter.iter_entries([('key1', )])))
822
        # ask for missing, get none
823
        self.assertEqual(set(),
824
            set(adapter.iter_entries([('key3', )])))
825
826
    def test_iter_entries_prefix(self):
827
        index, adapter = self.make_index(key_elements=3, nodes=[
828
            (('notprefix', 'foo', 'key1'), 'data', ((), )),
829
            (('prefix', 'prefix2', 'key1'), 'data1', ((), )),
830
            (('prefix', 'prefix2', 'key2'), 'data2', ((('prefix', 'prefix2', 'key1'),),))])
831
        # ask for a prefix, get the results for just that prefix, adjusted.
2624.2.14 by Robert Collins
Add source index to the index iteration API to allow mapping back to the origin of retrieved data.
832
        self.assertEqual(set([(index, ('prefix2', 'key1', ), 'data1', ((),)),
833
            (index, ('prefix2', 'key2', ), 'data2', ((('prefix2', 'key1', ),),))]),
2624.2.12 by Robert Collins
Create an adapter between indices with differing key lengths.
834
            set(adapter.iter_entries_prefix([('prefix2', None)])))
835
836
    def test_validate(self):
837
        index, adapter = self.make_index()
838
        calls = []
839
        def validate():
840
            calls.append('called')
841
        index.validate = validate
842
        adapter.validate()
843
        self.assertEqual(['called'], calls)