##// END OF EJS Templates
storageutil: consistently raise LookupError (API)...
Gregory Szorc -
r40039:ad8389ec default
parent child Browse files
Show More
@@ -1,1039 +1,1039 b''
1 # storage.py - Testing of storage primitives.
1 # storage.py - Testing of storage primitives.
2 #
2 #
3 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import unittest
10 import unittest
11
11
12 from ..node import (
12 from ..node import (
13 hex,
13 hex,
14 nullid,
14 nullid,
15 nullrev,
15 nullrev,
16 )
16 )
17 from .. import (
17 from .. import (
18 error,
18 error,
19 mdiff,
19 mdiff,
20 revlog,
20 revlog,
21 )
21 )
22 from ..utils import (
22 from ..utils import (
23 storageutil,
23 storageutil,
24 )
24 )
25
25
26 class basetestcase(unittest.TestCase):
26 class basetestcase(unittest.TestCase):
27 if not getattr(unittest.TestCase, r'assertRaisesRegex', False):
27 if not getattr(unittest.TestCase, r'assertRaisesRegex', False):
28 assertRaisesRegex = (# camelcase-required
28 assertRaisesRegex = (# camelcase-required
29 unittest.TestCase.assertRaisesRegexp)
29 unittest.TestCase.assertRaisesRegexp)
30
30
31 class ifileindextests(basetestcase):
31 class ifileindextests(basetestcase):
32 """Generic tests for the ifileindex interface.
32 """Generic tests for the ifileindex interface.
33
33
34 All file storage backends for index data should conform to the tests in this
34 All file storage backends for index data should conform to the tests in this
35 class.
35 class.
36
36
37 Use ``makeifileindextests()`` to create an instance of this type.
37 Use ``makeifileindextests()`` to create an instance of this type.
38 """
38 """
39 def testempty(self):
39 def testempty(self):
40 f = self._makefilefn()
40 f = self._makefilefn()
41 self.assertEqual(len(f), 0, 'new file store has 0 length by default')
41 self.assertEqual(len(f), 0, 'new file store has 0 length by default')
42 self.assertEqual(list(f), [], 'iter yields nothing by default')
42 self.assertEqual(list(f), [], 'iter yields nothing by default')
43
43
44 gen = iter(f)
44 gen = iter(f)
45 with self.assertRaises(StopIteration):
45 with self.assertRaises(StopIteration):
46 next(gen)
46 next(gen)
47
47
48 # revs() should evaluate to an empty list.
48 # revs() should evaluate to an empty list.
49 self.assertEqual(list(f.revs()), [])
49 self.assertEqual(list(f.revs()), [])
50
50
51 revs = iter(f.revs())
51 revs = iter(f.revs())
52 with self.assertRaises(StopIteration):
52 with self.assertRaises(StopIteration):
53 next(revs)
53 next(revs)
54
54
55 self.assertEqual(list(f.revs(start=20)), [])
55 self.assertEqual(list(f.revs(start=20)), [])
56
56
57 # parents() and parentrevs() work with nullid/nullrev.
57 # parents() and parentrevs() work with nullid/nullrev.
58 self.assertEqual(f.parents(nullid), (nullid, nullid))
58 self.assertEqual(f.parents(nullid), (nullid, nullid))
59 self.assertEqual(f.parentrevs(nullrev), (nullrev, nullrev))
59 self.assertEqual(f.parentrevs(nullrev), (nullrev, nullrev))
60
60
61 with self.assertRaises(error.LookupError):
61 with self.assertRaises(error.LookupError):
62 f.parents(b'\x01' * 20)
62 f.parents(b'\x01' * 20)
63
63
64 for i in range(-5, 5):
64 for i in range(-5, 5):
65 if i == nullrev:
65 if i == nullrev:
66 continue
66 continue
67
67
68 with self.assertRaises(IndexError):
68 with self.assertRaises(IndexError):
69 f.parentrevs(i)
69 f.parentrevs(i)
70
70
71 # nullid/nullrev lookup always works.
71 # nullid/nullrev lookup always works.
72 self.assertEqual(f.rev(nullid), nullrev)
72 self.assertEqual(f.rev(nullid), nullrev)
73 self.assertEqual(f.node(nullrev), nullid)
73 self.assertEqual(f.node(nullrev), nullid)
74
74
75 with self.assertRaises(error.LookupError):
75 with self.assertRaises(error.LookupError):
76 f.rev(b'\x01' * 20)
76 f.rev(b'\x01' * 20)
77
77
78 for i in range(-5, 5):
78 for i in range(-5, 5):
79 if i == nullrev:
79 if i == nullrev:
80 continue
80 continue
81
81
82 with self.assertRaises(IndexError):
82 with self.assertRaises(IndexError):
83 f.node(i)
83 f.node(i)
84
84
85 self.assertEqual(f.lookup(nullid), nullid)
85 self.assertEqual(f.lookup(nullid), nullid)
86 self.assertEqual(f.lookup(nullrev), nullid)
86 self.assertEqual(f.lookup(nullrev), nullid)
87 self.assertEqual(f.lookup(hex(nullid)), nullid)
87 self.assertEqual(f.lookup(hex(nullid)), nullid)
88 self.assertEqual(f.lookup(b'%d' % nullrev), nullid)
88 self.assertEqual(f.lookup(b'%d' % nullrev), nullid)
89
89
90 with self.assertRaises(error.LookupError):
90 with self.assertRaises(error.LookupError):
91 f.lookup(b'badvalue')
91 f.lookup(b'badvalue')
92
92
93 with self.assertRaises(error.LookupError):
93 with self.assertRaises(error.LookupError):
94 f.lookup(hex(nullid)[0:12])
94 f.lookup(hex(nullid)[0:12])
95
95
96 with self.assertRaises(error.LookupError):
96 with self.assertRaises(error.LookupError):
97 f.lookup(b'-2')
97 f.lookup(b'-2')
98
98
99 with self.assertRaises(error.LookupError):
99 with self.assertRaises(error.LookupError):
100 f.lookup(b'0')
100 f.lookup(b'0')
101
101
102 with self.assertRaises(error.LookupError):
102 with self.assertRaises(error.LookupError):
103 f.lookup(b'1')
103 f.lookup(b'1')
104
104
105 with self.assertRaises(error.LookupError):
105 with self.assertRaises(error.LookupError):
106 f.lookup(b'11111111111111111111111111111111111111')
106 f.lookup(b'11111111111111111111111111111111111111')
107
107
108 for i in range(-5, 5):
108 for i in range(-5, 5):
109 if i == nullrev:
109 if i == nullrev:
110 continue
110 continue
111
111
112 with self.assertRaises(LookupError):
112 with self.assertRaises(LookupError):
113 f.lookup(i)
113 f.lookup(i)
114
114
115 self.assertEqual(f.linkrev(nullrev), nullrev)
115 self.assertEqual(f.linkrev(nullrev), nullrev)
116
116
117 for i in range(-5, 5):
117 for i in range(-5, 5):
118 if i == nullrev:
118 if i == nullrev:
119 continue
119 continue
120
120
121 with self.assertRaises(IndexError):
121 with self.assertRaises(IndexError):
122 f.linkrev(i)
122 f.linkrev(i)
123
123
124 self.assertFalse(f.iscensored(nullrev))
124 self.assertFalse(f.iscensored(nullrev))
125
125
126 for i in range(-5, 5):
126 for i in range(-5, 5):
127 if i == nullrev:
127 if i == nullrev:
128 continue
128 continue
129
129
130 with self.assertRaises(IndexError):
130 with self.assertRaises(IndexError):
131 f.iscensored(i)
131 f.iscensored(i)
132
132
133 self.assertEqual(list(f.commonancestorsheads(nullid, nullid)), [])
133 self.assertEqual(list(f.commonancestorsheads(nullid, nullid)), [])
134
134
135 with self.assertRaises(ValueError):
135 with self.assertRaises(ValueError):
136 self.assertEqual(list(f.descendants([])), [])
136 self.assertEqual(list(f.descendants([])), [])
137
137
138 self.assertEqual(list(f.descendants([nullrev])), [])
138 self.assertEqual(list(f.descendants([nullrev])), [])
139
139
140 self.assertEqual(f.heads(), [nullid])
140 self.assertEqual(f.heads(), [nullid])
141 self.assertEqual(f.heads(nullid), [nullid])
141 self.assertEqual(f.heads(nullid), [nullid])
142 self.assertEqual(f.heads(None, [nullid]), [nullid])
142 self.assertEqual(f.heads(None, [nullid]), [nullid])
143 self.assertEqual(f.heads(nullid, [nullid]), [nullid])
143 self.assertEqual(f.heads(nullid, [nullid]), [nullid])
144
144
145 self.assertEqual(f.children(nullid), [])
145 self.assertEqual(f.children(nullid), [])
146
146
147 with self.assertRaises(error.LookupError):
147 with self.assertRaises(error.LookupError):
148 f.children(b'\x01' * 20)
148 f.children(b'\x01' * 20)
149
149
150 def testsinglerevision(self):
150 def testsinglerevision(self):
151 f = self._makefilefn()
151 f = self._makefilefn()
152 with self._maketransactionfn() as tr:
152 with self._maketransactionfn() as tr:
153 node = f.add(b'initial', None, tr, 0, nullid, nullid)
153 node = f.add(b'initial', None, tr, 0, nullid, nullid)
154
154
155 self.assertEqual(len(f), 1)
155 self.assertEqual(len(f), 1)
156 self.assertEqual(list(f), [0])
156 self.assertEqual(list(f), [0])
157
157
158 gen = iter(f)
158 gen = iter(f)
159 self.assertEqual(next(gen), 0)
159 self.assertEqual(next(gen), 0)
160
160
161 with self.assertRaises(StopIteration):
161 with self.assertRaises(StopIteration):
162 next(gen)
162 next(gen)
163
163
164 self.assertEqual(list(f.revs()), [0])
164 self.assertEqual(list(f.revs()), [0])
165 self.assertEqual(list(f.revs(start=1)), [])
165 self.assertEqual(list(f.revs(start=1)), [])
166 self.assertEqual(list(f.revs(start=0)), [0])
166 self.assertEqual(list(f.revs(start=0)), [0])
167 self.assertEqual(list(f.revs(stop=0)), [0])
167 self.assertEqual(list(f.revs(stop=0)), [0])
168 self.assertEqual(list(f.revs(stop=1)), [0])
168 self.assertEqual(list(f.revs(stop=1)), [0])
169 self.assertEqual(list(f.revs(1, 1)), [])
169 self.assertEqual(list(f.revs(1, 1)), [])
170 # TODO buggy
170 # TODO buggy
171 self.assertEqual(list(f.revs(1, 0)), [1, 0])
171 self.assertEqual(list(f.revs(1, 0)), [1, 0])
172 self.assertEqual(list(f.revs(2, 0)), [2, 1, 0])
172 self.assertEqual(list(f.revs(2, 0)), [2, 1, 0])
173
173
174 self.assertEqual(f.parents(node), (nullid, nullid))
174 self.assertEqual(f.parents(node), (nullid, nullid))
175 self.assertEqual(f.parentrevs(0), (nullrev, nullrev))
175 self.assertEqual(f.parentrevs(0), (nullrev, nullrev))
176
176
177 with self.assertRaises(error.LookupError):
177 with self.assertRaises(error.LookupError):
178 f.parents(b'\x01' * 20)
178 f.parents(b'\x01' * 20)
179
179
180 with self.assertRaises(IndexError):
180 with self.assertRaises(IndexError):
181 f.parentrevs(1)
181 f.parentrevs(1)
182
182
183 self.assertEqual(f.rev(node), 0)
183 self.assertEqual(f.rev(node), 0)
184
184
185 with self.assertRaises(error.LookupError):
185 with self.assertRaises(error.LookupError):
186 f.rev(b'\x01' * 20)
186 f.rev(b'\x01' * 20)
187
187
188 self.assertEqual(f.node(0), node)
188 self.assertEqual(f.node(0), node)
189
189
190 with self.assertRaises(IndexError):
190 with self.assertRaises(IndexError):
191 f.node(1)
191 f.node(1)
192
192
193 self.assertEqual(f.lookup(node), node)
193 self.assertEqual(f.lookup(node), node)
194 self.assertEqual(f.lookup(0), node)
194 self.assertEqual(f.lookup(0), node)
195 self.assertEqual(f.lookup(-1), nullid)
195 self.assertEqual(f.lookup(-1), nullid)
196 self.assertEqual(f.lookup(b'0'), node)
196 self.assertEqual(f.lookup(b'0'), node)
197 self.assertEqual(f.lookup(hex(node)), node)
197 self.assertEqual(f.lookup(hex(node)), node)
198
198
199 with self.assertRaises(error.LookupError):
199 with self.assertRaises(error.LookupError):
200 f.lookup(hex(node)[0:12])
200 f.lookup(hex(node)[0:12])
201
201
202 with self.assertRaises(IndexError):
202 with self.assertRaises(error.LookupError):
203 f.lookup(-2)
203 f.lookup(-2)
204
204
205 with self.assertRaises(error.LookupError):
205 with self.assertRaises(error.LookupError):
206 f.lookup(b'-2')
206 f.lookup(b'-2')
207
207
208 with self.assertRaises(IndexError):
208 with self.assertRaises(error.LookupError):
209 f.lookup(1)
209 f.lookup(1)
210
210
211 with self.assertRaises(error.LookupError):
211 with self.assertRaises(error.LookupError):
212 f.lookup(b'1')
212 f.lookup(b'1')
213
213
214 self.assertEqual(f.linkrev(0), 0)
214 self.assertEqual(f.linkrev(0), 0)
215
215
216 with self.assertRaises(IndexError):
216 with self.assertRaises(IndexError):
217 f.linkrev(1)
217 f.linkrev(1)
218
218
219 self.assertFalse(f.iscensored(0))
219 self.assertFalse(f.iscensored(0))
220
220
221 with self.assertRaises(IndexError):
221 with self.assertRaises(IndexError):
222 f.iscensored(1)
222 f.iscensored(1)
223
223
224 self.assertEqual(list(f.descendants([0])), [])
224 self.assertEqual(list(f.descendants([0])), [])
225
225
226 self.assertEqual(f.heads(), [node])
226 self.assertEqual(f.heads(), [node])
227 self.assertEqual(f.heads(node), [node])
227 self.assertEqual(f.heads(node), [node])
228 self.assertEqual(f.heads(stop=[node]), [node])
228 self.assertEqual(f.heads(stop=[node]), [node])
229
229
230 with self.assertRaises(error.LookupError):
230 with self.assertRaises(error.LookupError):
231 f.heads(stop=[b'\x01' * 20])
231 f.heads(stop=[b'\x01' * 20])
232
232
233 self.assertEqual(f.children(node), [])
233 self.assertEqual(f.children(node), [])
234
234
235 def testmultiplerevisions(self):
235 def testmultiplerevisions(self):
236 fulltext0 = b'x' * 1024
236 fulltext0 = b'x' * 1024
237 fulltext1 = fulltext0 + b'y'
237 fulltext1 = fulltext0 + b'y'
238 fulltext2 = b'y' + fulltext0 + b'z'
238 fulltext2 = b'y' + fulltext0 + b'z'
239
239
240 f = self._makefilefn()
240 f = self._makefilefn()
241 with self._maketransactionfn() as tr:
241 with self._maketransactionfn() as tr:
242 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
242 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
243 node1 = f.add(fulltext1, None, tr, 1, node0, nullid)
243 node1 = f.add(fulltext1, None, tr, 1, node0, nullid)
244 node2 = f.add(fulltext2, None, tr, 3, node1, nullid)
244 node2 = f.add(fulltext2, None, tr, 3, node1, nullid)
245
245
246 self.assertEqual(len(f), 3)
246 self.assertEqual(len(f), 3)
247 self.assertEqual(list(f), [0, 1, 2])
247 self.assertEqual(list(f), [0, 1, 2])
248
248
249 gen = iter(f)
249 gen = iter(f)
250 self.assertEqual(next(gen), 0)
250 self.assertEqual(next(gen), 0)
251 self.assertEqual(next(gen), 1)
251 self.assertEqual(next(gen), 1)
252 self.assertEqual(next(gen), 2)
252 self.assertEqual(next(gen), 2)
253
253
254 with self.assertRaises(StopIteration):
254 with self.assertRaises(StopIteration):
255 next(gen)
255 next(gen)
256
256
257 self.assertEqual(list(f.revs()), [0, 1, 2])
257 self.assertEqual(list(f.revs()), [0, 1, 2])
258 self.assertEqual(list(f.revs(0)), [0, 1, 2])
258 self.assertEqual(list(f.revs(0)), [0, 1, 2])
259 self.assertEqual(list(f.revs(1)), [1, 2])
259 self.assertEqual(list(f.revs(1)), [1, 2])
260 self.assertEqual(list(f.revs(2)), [2])
260 self.assertEqual(list(f.revs(2)), [2])
261 self.assertEqual(list(f.revs(3)), [])
261 self.assertEqual(list(f.revs(3)), [])
262 self.assertEqual(list(f.revs(stop=1)), [0, 1])
262 self.assertEqual(list(f.revs(stop=1)), [0, 1])
263 self.assertEqual(list(f.revs(stop=2)), [0, 1, 2])
263 self.assertEqual(list(f.revs(stop=2)), [0, 1, 2])
264 self.assertEqual(list(f.revs(stop=3)), [0, 1, 2])
264 self.assertEqual(list(f.revs(stop=3)), [0, 1, 2])
265 self.assertEqual(list(f.revs(2, 0)), [2, 1, 0])
265 self.assertEqual(list(f.revs(2, 0)), [2, 1, 0])
266 self.assertEqual(list(f.revs(2, 1)), [2, 1])
266 self.assertEqual(list(f.revs(2, 1)), [2, 1])
267 # TODO this is wrong
267 # TODO this is wrong
268 self.assertEqual(list(f.revs(3, 2)), [3, 2])
268 self.assertEqual(list(f.revs(3, 2)), [3, 2])
269
269
270 self.assertEqual(f.parents(node0), (nullid, nullid))
270 self.assertEqual(f.parents(node0), (nullid, nullid))
271 self.assertEqual(f.parents(node1), (node0, nullid))
271 self.assertEqual(f.parents(node1), (node0, nullid))
272 self.assertEqual(f.parents(node2), (node1, nullid))
272 self.assertEqual(f.parents(node2), (node1, nullid))
273
273
274 self.assertEqual(f.parentrevs(0), (nullrev, nullrev))
274 self.assertEqual(f.parentrevs(0), (nullrev, nullrev))
275 self.assertEqual(f.parentrevs(1), (0, nullrev))
275 self.assertEqual(f.parentrevs(1), (0, nullrev))
276 self.assertEqual(f.parentrevs(2), (1, nullrev))
276 self.assertEqual(f.parentrevs(2), (1, nullrev))
277
277
278 self.assertEqual(f.rev(node0), 0)
278 self.assertEqual(f.rev(node0), 0)
279 self.assertEqual(f.rev(node1), 1)
279 self.assertEqual(f.rev(node1), 1)
280 self.assertEqual(f.rev(node2), 2)
280 self.assertEqual(f.rev(node2), 2)
281
281
282 with self.assertRaises(error.LookupError):
282 with self.assertRaises(error.LookupError):
283 f.rev(b'\x01' * 20)
283 f.rev(b'\x01' * 20)
284
284
285 self.assertEqual(f.node(0), node0)
285 self.assertEqual(f.node(0), node0)
286 self.assertEqual(f.node(1), node1)
286 self.assertEqual(f.node(1), node1)
287 self.assertEqual(f.node(2), node2)
287 self.assertEqual(f.node(2), node2)
288
288
289 with self.assertRaises(IndexError):
289 with self.assertRaises(IndexError):
290 f.node(3)
290 f.node(3)
291
291
292 self.assertEqual(f.lookup(node0), node0)
292 self.assertEqual(f.lookup(node0), node0)
293 self.assertEqual(f.lookup(0), node0)
293 self.assertEqual(f.lookup(0), node0)
294 self.assertEqual(f.lookup(b'0'), node0)
294 self.assertEqual(f.lookup(b'0'), node0)
295 self.assertEqual(f.lookup(hex(node0)), node0)
295 self.assertEqual(f.lookup(hex(node0)), node0)
296
296
297 self.assertEqual(f.lookup(node1), node1)
297 self.assertEqual(f.lookup(node1), node1)
298 self.assertEqual(f.lookup(1), node1)
298 self.assertEqual(f.lookup(1), node1)
299 self.assertEqual(f.lookup(b'1'), node1)
299 self.assertEqual(f.lookup(b'1'), node1)
300 self.assertEqual(f.lookup(hex(node1)), node1)
300 self.assertEqual(f.lookup(hex(node1)), node1)
301
301
302 self.assertEqual(f.linkrev(0), 0)
302 self.assertEqual(f.linkrev(0), 0)
303 self.assertEqual(f.linkrev(1), 1)
303 self.assertEqual(f.linkrev(1), 1)
304 self.assertEqual(f.linkrev(2), 3)
304 self.assertEqual(f.linkrev(2), 3)
305
305
306 with self.assertRaises(IndexError):
306 with self.assertRaises(IndexError):
307 f.linkrev(3)
307 f.linkrev(3)
308
308
309 self.assertFalse(f.iscensored(0))
309 self.assertFalse(f.iscensored(0))
310 self.assertFalse(f.iscensored(1))
310 self.assertFalse(f.iscensored(1))
311 self.assertFalse(f.iscensored(2))
311 self.assertFalse(f.iscensored(2))
312
312
313 with self.assertRaises(IndexError):
313 with self.assertRaises(IndexError):
314 f.iscensored(3)
314 f.iscensored(3)
315
315
316 self.assertEqual(f.commonancestorsheads(node1, nullid), [])
316 self.assertEqual(f.commonancestorsheads(node1, nullid), [])
317 self.assertEqual(f.commonancestorsheads(node1, node0), [node0])
317 self.assertEqual(f.commonancestorsheads(node1, node0), [node0])
318 self.assertEqual(f.commonancestorsheads(node1, node1), [node1])
318 self.assertEqual(f.commonancestorsheads(node1, node1), [node1])
319 self.assertEqual(f.commonancestorsheads(node0, node1), [node0])
319 self.assertEqual(f.commonancestorsheads(node0, node1), [node0])
320 self.assertEqual(f.commonancestorsheads(node1, node2), [node1])
320 self.assertEqual(f.commonancestorsheads(node1, node2), [node1])
321 self.assertEqual(f.commonancestorsheads(node2, node1), [node1])
321 self.assertEqual(f.commonancestorsheads(node2, node1), [node1])
322
322
323 self.assertEqual(list(f.descendants([0])), [1, 2])
323 self.assertEqual(list(f.descendants([0])), [1, 2])
324 self.assertEqual(list(f.descendants([1])), [2])
324 self.assertEqual(list(f.descendants([1])), [2])
325 self.assertEqual(list(f.descendants([0, 1])), [1, 2])
325 self.assertEqual(list(f.descendants([0, 1])), [1, 2])
326
326
327 self.assertEqual(f.heads(), [node2])
327 self.assertEqual(f.heads(), [node2])
328 self.assertEqual(f.heads(node0), [node2])
328 self.assertEqual(f.heads(node0), [node2])
329 self.assertEqual(f.heads(node1), [node2])
329 self.assertEqual(f.heads(node1), [node2])
330 self.assertEqual(f.heads(node2), [node2])
330 self.assertEqual(f.heads(node2), [node2])
331
331
332 # TODO this behavior seems wonky. Is it correct? If so, the
332 # TODO this behavior seems wonky. Is it correct? If so, the
333 # docstring for heads() should be updated to reflect desired
333 # docstring for heads() should be updated to reflect desired
334 # behavior.
334 # behavior.
335 self.assertEqual(f.heads(stop=[node1]), [node1, node2])
335 self.assertEqual(f.heads(stop=[node1]), [node1, node2])
336 self.assertEqual(f.heads(stop=[node0]), [node0, node2])
336 self.assertEqual(f.heads(stop=[node0]), [node0, node2])
337 self.assertEqual(f.heads(stop=[node1, node2]), [node1, node2])
337 self.assertEqual(f.heads(stop=[node1, node2]), [node1, node2])
338
338
339 with self.assertRaises(error.LookupError):
339 with self.assertRaises(error.LookupError):
340 f.heads(stop=[b'\x01' * 20])
340 f.heads(stop=[b'\x01' * 20])
341
341
342 self.assertEqual(f.children(node0), [node1])
342 self.assertEqual(f.children(node0), [node1])
343 self.assertEqual(f.children(node1), [node2])
343 self.assertEqual(f.children(node1), [node2])
344 self.assertEqual(f.children(node2), [])
344 self.assertEqual(f.children(node2), [])
345
345
346 def testmultipleheads(self):
346 def testmultipleheads(self):
347 f = self._makefilefn()
347 f = self._makefilefn()
348
348
349 with self._maketransactionfn() as tr:
349 with self._maketransactionfn() as tr:
350 node0 = f.add(b'0', None, tr, 0, nullid, nullid)
350 node0 = f.add(b'0', None, tr, 0, nullid, nullid)
351 node1 = f.add(b'1', None, tr, 1, node0, nullid)
351 node1 = f.add(b'1', None, tr, 1, node0, nullid)
352 node2 = f.add(b'2', None, tr, 2, node1, nullid)
352 node2 = f.add(b'2', None, tr, 2, node1, nullid)
353 node3 = f.add(b'3', None, tr, 3, node0, nullid)
353 node3 = f.add(b'3', None, tr, 3, node0, nullid)
354 node4 = f.add(b'4', None, tr, 4, node3, nullid)
354 node4 = f.add(b'4', None, tr, 4, node3, nullid)
355 node5 = f.add(b'5', None, tr, 5, node0, nullid)
355 node5 = f.add(b'5', None, tr, 5, node0, nullid)
356
356
357 self.assertEqual(len(f), 6)
357 self.assertEqual(len(f), 6)
358
358
359 self.assertEqual(list(f.descendants([0])), [1, 2, 3, 4, 5])
359 self.assertEqual(list(f.descendants([0])), [1, 2, 3, 4, 5])
360 self.assertEqual(list(f.descendants([1])), [2])
360 self.assertEqual(list(f.descendants([1])), [2])
361 self.assertEqual(list(f.descendants([2])), [])
361 self.assertEqual(list(f.descendants([2])), [])
362 self.assertEqual(list(f.descendants([3])), [4])
362 self.assertEqual(list(f.descendants([3])), [4])
363 self.assertEqual(list(f.descendants([0, 1])), [1, 2, 3, 4, 5])
363 self.assertEqual(list(f.descendants([0, 1])), [1, 2, 3, 4, 5])
364 self.assertEqual(list(f.descendants([1, 3])), [2, 4])
364 self.assertEqual(list(f.descendants([1, 3])), [2, 4])
365
365
366 self.assertEqual(f.heads(), [node2, node4, node5])
366 self.assertEqual(f.heads(), [node2, node4, node5])
367 self.assertEqual(f.heads(node0), [node2, node4, node5])
367 self.assertEqual(f.heads(node0), [node2, node4, node5])
368 self.assertEqual(f.heads(node1), [node2])
368 self.assertEqual(f.heads(node1), [node2])
369 self.assertEqual(f.heads(node2), [node2])
369 self.assertEqual(f.heads(node2), [node2])
370 self.assertEqual(f.heads(node3), [node4])
370 self.assertEqual(f.heads(node3), [node4])
371 self.assertEqual(f.heads(node4), [node4])
371 self.assertEqual(f.heads(node4), [node4])
372 self.assertEqual(f.heads(node5), [node5])
372 self.assertEqual(f.heads(node5), [node5])
373
373
374 # TODO this seems wrong.
374 # TODO this seems wrong.
375 self.assertEqual(f.heads(stop=[node0]), [node0, node2, node4, node5])
375 self.assertEqual(f.heads(stop=[node0]), [node0, node2, node4, node5])
376 self.assertEqual(f.heads(stop=[node1]), [node1, node2, node4, node5])
376 self.assertEqual(f.heads(stop=[node1]), [node1, node2, node4, node5])
377
377
378 self.assertEqual(f.children(node0), [node1, node3, node5])
378 self.assertEqual(f.children(node0), [node1, node3, node5])
379 self.assertEqual(f.children(node1), [node2])
379 self.assertEqual(f.children(node1), [node2])
380 self.assertEqual(f.children(node2), [])
380 self.assertEqual(f.children(node2), [])
381 self.assertEqual(f.children(node3), [node4])
381 self.assertEqual(f.children(node3), [node4])
382 self.assertEqual(f.children(node4), [])
382 self.assertEqual(f.children(node4), [])
383 self.assertEqual(f.children(node5), [])
383 self.assertEqual(f.children(node5), [])
384
384
385 class ifiledatatests(basetestcase):
385 class ifiledatatests(basetestcase):
386 """Generic tests for the ifiledata interface.
386 """Generic tests for the ifiledata interface.
387
387
388 All file storage backends for data should conform to the tests in this
388 All file storage backends for data should conform to the tests in this
389 class.
389 class.
390
390
391 Use ``makeifiledatatests()`` to create an instance of this type.
391 Use ``makeifiledatatests()`` to create an instance of this type.
392 """
392 """
393 def testempty(self):
393 def testempty(self):
394 f = self._makefilefn()
394 f = self._makefilefn()
395
395
396 self.assertEqual(f.storageinfo(), {})
396 self.assertEqual(f.storageinfo(), {})
397 self.assertEqual(f.storageinfo(revisionscount=True, trackedsize=True),
397 self.assertEqual(f.storageinfo(revisionscount=True, trackedsize=True),
398 {'revisionscount': 0, 'trackedsize': 0})
398 {'revisionscount': 0, 'trackedsize': 0})
399
399
400 self.assertEqual(f.size(nullrev), 0)
400 self.assertEqual(f.size(nullrev), 0)
401
401
402 for i in range(-5, 5):
402 for i in range(-5, 5):
403 if i == nullrev:
403 if i == nullrev:
404 continue
404 continue
405
405
406 with self.assertRaises(IndexError):
406 with self.assertRaises(IndexError):
407 f.size(i)
407 f.size(i)
408
408
409 self.assertEqual(f.revision(nullid), b'')
409 self.assertEqual(f.revision(nullid), b'')
410 self.assertEqual(f.revision(nullid, raw=True), b'')
410 self.assertEqual(f.revision(nullid, raw=True), b'')
411
411
412 with self.assertRaises(error.LookupError):
412 with self.assertRaises(error.LookupError):
413 f.revision(b'\x01' * 20)
413 f.revision(b'\x01' * 20)
414
414
415 self.assertEqual(f.read(nullid), b'')
415 self.assertEqual(f.read(nullid), b'')
416
416
417 with self.assertRaises(error.LookupError):
417 with self.assertRaises(error.LookupError):
418 f.read(b'\x01' * 20)
418 f.read(b'\x01' * 20)
419
419
420 self.assertFalse(f.renamed(nullid))
420 self.assertFalse(f.renamed(nullid))
421
421
422 with self.assertRaises(error.LookupError):
422 with self.assertRaises(error.LookupError):
423 f.read(b'\x01' * 20)
423 f.read(b'\x01' * 20)
424
424
425 self.assertTrue(f.cmp(nullid, b''))
425 self.assertTrue(f.cmp(nullid, b''))
426 self.assertTrue(f.cmp(nullid, b'foo'))
426 self.assertTrue(f.cmp(nullid, b'foo'))
427
427
428 with self.assertRaises(error.LookupError):
428 with self.assertRaises(error.LookupError):
429 f.cmp(b'\x01' * 20, b'irrelevant')
429 f.cmp(b'\x01' * 20, b'irrelevant')
430
430
431 # Emitting empty list is an empty generator.
431 # Emitting empty list is an empty generator.
432 gen = f.emitrevisions([])
432 gen = f.emitrevisions([])
433 with self.assertRaises(StopIteration):
433 with self.assertRaises(StopIteration):
434 next(gen)
434 next(gen)
435
435
436 # Emitting null node yields nothing.
436 # Emitting null node yields nothing.
437 gen = f.emitrevisions([nullid])
437 gen = f.emitrevisions([nullid])
438 with self.assertRaises(StopIteration):
438 with self.assertRaises(StopIteration):
439 next(gen)
439 next(gen)
440
440
441 # Requesting unknown node fails.
441 # Requesting unknown node fails.
442 with self.assertRaises(error.LookupError):
442 with self.assertRaises(error.LookupError):
443 list(f.emitrevisions([b'\x01' * 20]))
443 list(f.emitrevisions([b'\x01' * 20]))
444
444
445 def testsinglerevision(self):
445 def testsinglerevision(self):
446 fulltext = b'initial'
446 fulltext = b'initial'
447
447
448 f = self._makefilefn()
448 f = self._makefilefn()
449 with self._maketransactionfn() as tr:
449 with self._maketransactionfn() as tr:
450 node = f.add(fulltext, None, tr, 0, nullid, nullid)
450 node = f.add(fulltext, None, tr, 0, nullid, nullid)
451
451
452 self.assertEqual(f.storageinfo(), {})
452 self.assertEqual(f.storageinfo(), {})
453 self.assertEqual(f.storageinfo(revisionscount=True, trackedsize=True),
453 self.assertEqual(f.storageinfo(revisionscount=True, trackedsize=True),
454 {'revisionscount': 1, 'trackedsize': len(fulltext)})
454 {'revisionscount': 1, 'trackedsize': len(fulltext)})
455
455
456 self.assertEqual(f.size(0), len(fulltext))
456 self.assertEqual(f.size(0), len(fulltext))
457
457
458 with self.assertRaises(IndexError):
458 with self.assertRaises(IndexError):
459 f.size(1)
459 f.size(1)
460
460
461 self.assertEqual(f.revision(node), fulltext)
461 self.assertEqual(f.revision(node), fulltext)
462 self.assertEqual(f.revision(node, raw=True), fulltext)
462 self.assertEqual(f.revision(node, raw=True), fulltext)
463
463
464 self.assertEqual(f.read(node), fulltext)
464 self.assertEqual(f.read(node), fulltext)
465
465
466 self.assertFalse(f.renamed(node))
466 self.assertFalse(f.renamed(node))
467
467
468 self.assertFalse(f.cmp(node, fulltext))
468 self.assertFalse(f.cmp(node, fulltext))
469 self.assertTrue(f.cmp(node, fulltext + b'extra'))
469 self.assertTrue(f.cmp(node, fulltext + b'extra'))
470
470
471 # Emitting a single revision works.
471 # Emitting a single revision works.
472 gen = f.emitrevisions([node])
472 gen = f.emitrevisions([node])
473 rev = next(gen)
473 rev = next(gen)
474
474
475 self.assertEqual(rev.node, node)
475 self.assertEqual(rev.node, node)
476 self.assertEqual(rev.p1node, nullid)
476 self.assertEqual(rev.p1node, nullid)
477 self.assertEqual(rev.p2node, nullid)
477 self.assertEqual(rev.p2node, nullid)
478 self.assertIsNone(rev.linknode)
478 self.assertIsNone(rev.linknode)
479 self.assertEqual(rev.basenode, nullid)
479 self.assertEqual(rev.basenode, nullid)
480 self.assertIsNone(rev.baserevisionsize)
480 self.assertIsNone(rev.baserevisionsize)
481 self.assertIsNone(rev.revision)
481 self.assertIsNone(rev.revision)
482 self.assertIsNone(rev.delta)
482 self.assertIsNone(rev.delta)
483
483
484 with self.assertRaises(StopIteration):
484 with self.assertRaises(StopIteration):
485 next(gen)
485 next(gen)
486
486
487 # Requesting revision data works.
487 # Requesting revision data works.
488 gen = f.emitrevisions([node], revisiondata=True)
488 gen = f.emitrevisions([node], revisiondata=True)
489 rev = next(gen)
489 rev = next(gen)
490
490
491 self.assertEqual(rev.node, node)
491 self.assertEqual(rev.node, node)
492 self.assertEqual(rev.p1node, nullid)
492 self.assertEqual(rev.p1node, nullid)
493 self.assertEqual(rev.p2node, nullid)
493 self.assertEqual(rev.p2node, nullid)
494 self.assertIsNone(rev.linknode)
494 self.assertIsNone(rev.linknode)
495 self.assertEqual(rev.basenode, nullid)
495 self.assertEqual(rev.basenode, nullid)
496 self.assertIsNone(rev.baserevisionsize)
496 self.assertIsNone(rev.baserevisionsize)
497 self.assertEqual(rev.revision, fulltext)
497 self.assertEqual(rev.revision, fulltext)
498 self.assertIsNone(rev.delta)
498 self.assertIsNone(rev.delta)
499
499
500 with self.assertRaises(StopIteration):
500 with self.assertRaises(StopIteration):
501 next(gen)
501 next(gen)
502
502
503 # Emitting an unknown node after a known revision results in error.
503 # Emitting an unknown node after a known revision results in error.
504 with self.assertRaises(error.LookupError):
504 with self.assertRaises(error.LookupError):
505 list(f.emitrevisions([node, b'\x01' * 20]))
505 list(f.emitrevisions([node, b'\x01' * 20]))
506
506
507 def testmultiplerevisions(self):
507 def testmultiplerevisions(self):
508 fulltext0 = b'x' * 1024
508 fulltext0 = b'x' * 1024
509 fulltext1 = fulltext0 + b'y'
509 fulltext1 = fulltext0 + b'y'
510 fulltext2 = b'y' + fulltext0 + b'z'
510 fulltext2 = b'y' + fulltext0 + b'z'
511
511
512 f = self._makefilefn()
512 f = self._makefilefn()
513 with self._maketransactionfn() as tr:
513 with self._maketransactionfn() as tr:
514 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
514 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
515 node1 = f.add(fulltext1, None, tr, 1, node0, nullid)
515 node1 = f.add(fulltext1, None, tr, 1, node0, nullid)
516 node2 = f.add(fulltext2, None, tr, 3, node1, nullid)
516 node2 = f.add(fulltext2, None, tr, 3, node1, nullid)
517
517
518 self.assertEqual(f.storageinfo(), {})
518 self.assertEqual(f.storageinfo(), {})
519 self.assertEqual(
519 self.assertEqual(
520 f.storageinfo(revisionscount=True, trackedsize=True),
520 f.storageinfo(revisionscount=True, trackedsize=True),
521 {
521 {
522 'revisionscount': 3,
522 'revisionscount': 3,
523 'trackedsize': len(fulltext0) + len(fulltext1) + len(fulltext2),
523 'trackedsize': len(fulltext0) + len(fulltext1) + len(fulltext2),
524 })
524 })
525
525
526 self.assertEqual(f.size(0), len(fulltext0))
526 self.assertEqual(f.size(0), len(fulltext0))
527 self.assertEqual(f.size(1), len(fulltext1))
527 self.assertEqual(f.size(1), len(fulltext1))
528 self.assertEqual(f.size(2), len(fulltext2))
528 self.assertEqual(f.size(2), len(fulltext2))
529
529
530 with self.assertRaises(IndexError):
530 with self.assertRaises(IndexError):
531 f.size(3)
531 f.size(3)
532
532
533 self.assertEqual(f.revision(node0), fulltext0)
533 self.assertEqual(f.revision(node0), fulltext0)
534 self.assertEqual(f.revision(node0, raw=True), fulltext0)
534 self.assertEqual(f.revision(node0, raw=True), fulltext0)
535 self.assertEqual(f.revision(node1), fulltext1)
535 self.assertEqual(f.revision(node1), fulltext1)
536 self.assertEqual(f.revision(node1, raw=True), fulltext1)
536 self.assertEqual(f.revision(node1, raw=True), fulltext1)
537 self.assertEqual(f.revision(node2), fulltext2)
537 self.assertEqual(f.revision(node2), fulltext2)
538 self.assertEqual(f.revision(node2, raw=True), fulltext2)
538 self.assertEqual(f.revision(node2, raw=True), fulltext2)
539
539
540 with self.assertRaises(error.LookupError):
540 with self.assertRaises(error.LookupError):
541 f.revision(b'\x01' * 20)
541 f.revision(b'\x01' * 20)
542
542
543 self.assertEqual(f.read(node0), fulltext0)
543 self.assertEqual(f.read(node0), fulltext0)
544 self.assertEqual(f.read(node1), fulltext1)
544 self.assertEqual(f.read(node1), fulltext1)
545 self.assertEqual(f.read(node2), fulltext2)
545 self.assertEqual(f.read(node2), fulltext2)
546
546
547 with self.assertRaises(error.LookupError):
547 with self.assertRaises(error.LookupError):
548 f.read(b'\x01' * 20)
548 f.read(b'\x01' * 20)
549
549
550 self.assertFalse(f.renamed(node0))
550 self.assertFalse(f.renamed(node0))
551 self.assertFalse(f.renamed(node1))
551 self.assertFalse(f.renamed(node1))
552 self.assertFalse(f.renamed(node2))
552 self.assertFalse(f.renamed(node2))
553
553
554 with self.assertRaises(error.LookupError):
554 with self.assertRaises(error.LookupError):
555 f.renamed(b'\x01' * 20)
555 f.renamed(b'\x01' * 20)
556
556
557 self.assertFalse(f.cmp(node0, fulltext0))
557 self.assertFalse(f.cmp(node0, fulltext0))
558 self.assertFalse(f.cmp(node1, fulltext1))
558 self.assertFalse(f.cmp(node1, fulltext1))
559 self.assertFalse(f.cmp(node2, fulltext2))
559 self.assertFalse(f.cmp(node2, fulltext2))
560
560
561 self.assertTrue(f.cmp(node1, fulltext0))
561 self.assertTrue(f.cmp(node1, fulltext0))
562 self.assertTrue(f.cmp(node2, fulltext1))
562 self.assertTrue(f.cmp(node2, fulltext1))
563
563
564 with self.assertRaises(error.LookupError):
564 with self.assertRaises(error.LookupError):
565 f.cmp(b'\x01' * 20, b'irrelevant')
565 f.cmp(b'\x01' * 20, b'irrelevant')
566
566
567 # Nodes should be emitted in order.
567 # Nodes should be emitted in order.
568 gen = f.emitrevisions([node0, node1, node2], revisiondata=True)
568 gen = f.emitrevisions([node0, node1, node2], revisiondata=True)
569
569
570 rev = next(gen)
570 rev = next(gen)
571
571
572 self.assertEqual(rev.node, node0)
572 self.assertEqual(rev.node, node0)
573 self.assertEqual(rev.p1node, nullid)
573 self.assertEqual(rev.p1node, nullid)
574 self.assertEqual(rev.p2node, nullid)
574 self.assertEqual(rev.p2node, nullid)
575 self.assertIsNone(rev.linknode)
575 self.assertIsNone(rev.linknode)
576 self.assertEqual(rev.basenode, nullid)
576 self.assertEqual(rev.basenode, nullid)
577 self.assertIsNone(rev.baserevisionsize)
577 self.assertIsNone(rev.baserevisionsize)
578 self.assertEqual(rev.revision, fulltext0)
578 self.assertEqual(rev.revision, fulltext0)
579 self.assertIsNone(rev.delta)
579 self.assertIsNone(rev.delta)
580
580
581 rev = next(gen)
581 rev = next(gen)
582
582
583 self.assertEqual(rev.node, node1)
583 self.assertEqual(rev.node, node1)
584 self.assertEqual(rev.p1node, node0)
584 self.assertEqual(rev.p1node, node0)
585 self.assertEqual(rev.p2node, nullid)
585 self.assertEqual(rev.p2node, nullid)
586 self.assertIsNone(rev.linknode)
586 self.assertIsNone(rev.linknode)
587 self.assertEqual(rev.basenode, node0)
587 self.assertEqual(rev.basenode, node0)
588 self.assertIsNone(rev.baserevisionsize)
588 self.assertIsNone(rev.baserevisionsize)
589 self.assertIsNone(rev.revision)
589 self.assertIsNone(rev.revision)
590 self.assertEqual(rev.delta,
590 self.assertEqual(rev.delta,
591 b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' +
591 b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' +
592 fulltext1)
592 fulltext1)
593
593
594 rev = next(gen)
594 rev = next(gen)
595
595
596 self.assertEqual(rev.node, node2)
596 self.assertEqual(rev.node, node2)
597 self.assertEqual(rev.p1node, node1)
597 self.assertEqual(rev.p1node, node1)
598 self.assertEqual(rev.p2node, nullid)
598 self.assertEqual(rev.p2node, nullid)
599 self.assertIsNone(rev.linknode)
599 self.assertIsNone(rev.linknode)
600 self.assertEqual(rev.basenode, node1)
600 self.assertEqual(rev.basenode, node1)
601 self.assertIsNone(rev.baserevisionsize)
601 self.assertIsNone(rev.baserevisionsize)
602 self.assertIsNone(rev.revision)
602 self.assertIsNone(rev.revision)
603 self.assertEqual(rev.delta,
603 self.assertEqual(rev.delta,
604 b'\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x04\x02' +
604 b'\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x04\x02' +
605 fulltext2)
605 fulltext2)
606
606
607 with self.assertRaises(StopIteration):
607 with self.assertRaises(StopIteration):
608 next(gen)
608 next(gen)
609
609
610 # Request not in DAG order is reordered to be in DAG order.
610 # Request not in DAG order is reordered to be in DAG order.
611 gen = f.emitrevisions([node2, node1, node0], revisiondata=True)
611 gen = f.emitrevisions([node2, node1, node0], revisiondata=True)
612
612
613 rev = next(gen)
613 rev = next(gen)
614
614
615 self.assertEqual(rev.node, node0)
615 self.assertEqual(rev.node, node0)
616 self.assertEqual(rev.p1node, nullid)
616 self.assertEqual(rev.p1node, nullid)
617 self.assertEqual(rev.p2node, nullid)
617 self.assertEqual(rev.p2node, nullid)
618 self.assertIsNone(rev.linknode)
618 self.assertIsNone(rev.linknode)
619 self.assertEqual(rev.basenode, nullid)
619 self.assertEqual(rev.basenode, nullid)
620 self.assertIsNone(rev.baserevisionsize)
620 self.assertIsNone(rev.baserevisionsize)
621 self.assertEqual(rev.revision, fulltext0)
621 self.assertEqual(rev.revision, fulltext0)
622 self.assertIsNone(rev.delta)
622 self.assertIsNone(rev.delta)
623
623
624 rev = next(gen)
624 rev = next(gen)
625
625
626 self.assertEqual(rev.node, node1)
626 self.assertEqual(rev.node, node1)
627 self.assertEqual(rev.p1node, node0)
627 self.assertEqual(rev.p1node, node0)
628 self.assertEqual(rev.p2node, nullid)
628 self.assertEqual(rev.p2node, nullid)
629 self.assertIsNone(rev.linknode)
629 self.assertIsNone(rev.linknode)
630 self.assertEqual(rev.basenode, node0)
630 self.assertEqual(rev.basenode, node0)
631 self.assertIsNone(rev.baserevisionsize)
631 self.assertIsNone(rev.baserevisionsize)
632 self.assertIsNone(rev.revision)
632 self.assertIsNone(rev.revision)
633 self.assertEqual(rev.delta,
633 self.assertEqual(rev.delta,
634 b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' +
634 b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' +
635 fulltext1)
635 fulltext1)
636
636
637 rev = next(gen)
637 rev = next(gen)
638
638
639 self.assertEqual(rev.node, node2)
639 self.assertEqual(rev.node, node2)
640 self.assertEqual(rev.p1node, node1)
640 self.assertEqual(rev.p1node, node1)
641 self.assertEqual(rev.p2node, nullid)
641 self.assertEqual(rev.p2node, nullid)
642 self.assertIsNone(rev.linknode)
642 self.assertIsNone(rev.linknode)
643 self.assertEqual(rev.basenode, node1)
643 self.assertEqual(rev.basenode, node1)
644 self.assertIsNone(rev.baserevisionsize)
644 self.assertIsNone(rev.baserevisionsize)
645 self.assertIsNone(rev.revision)
645 self.assertIsNone(rev.revision)
646 self.assertEqual(rev.delta,
646 self.assertEqual(rev.delta,
647 b'\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x04\x02' +
647 b'\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x04\x02' +
648 fulltext2)
648 fulltext2)
649
649
650 with self.assertRaises(StopIteration):
650 with self.assertRaises(StopIteration):
651 next(gen)
651 next(gen)
652
652
653 # Unrecognized nodesorder value raises ProgrammingError.
653 # Unrecognized nodesorder value raises ProgrammingError.
654 with self.assertRaises(error.ProgrammingError):
654 with self.assertRaises(error.ProgrammingError):
655 list(f.emitrevisions([], nodesorder='bad'))
655 list(f.emitrevisions([], nodesorder='bad'))
656
656
657 # nodesorder=storage is recognized. But we can't test it thoroughly
657 # nodesorder=storage is recognized. But we can't test it thoroughly
658 # because behavior is storage-dependent.
658 # because behavior is storage-dependent.
659 res = list(f.emitrevisions([node2, node1, node0],
659 res = list(f.emitrevisions([node2, node1, node0],
660 nodesorder='storage'))
660 nodesorder='storage'))
661 self.assertEqual(len(res), 3)
661 self.assertEqual(len(res), 3)
662 self.assertEqual({o.node for o in res}, {node0, node1, node2})
662 self.assertEqual({o.node for o in res}, {node0, node1, node2})
663
663
664 # nodesorder=nodes forces the order.
664 # nodesorder=nodes forces the order.
665 gen = f.emitrevisions([node2, node0], nodesorder='nodes',
665 gen = f.emitrevisions([node2, node0], nodesorder='nodes',
666 revisiondata=True)
666 revisiondata=True)
667
667
668 rev = next(gen)
668 rev = next(gen)
669 self.assertEqual(rev.node, node2)
669 self.assertEqual(rev.node, node2)
670 self.assertEqual(rev.p1node, node1)
670 self.assertEqual(rev.p1node, node1)
671 self.assertEqual(rev.p2node, nullid)
671 self.assertEqual(rev.p2node, nullid)
672 self.assertEqual(rev.basenode, nullid)
672 self.assertEqual(rev.basenode, nullid)
673 self.assertIsNone(rev.baserevisionsize)
673 self.assertIsNone(rev.baserevisionsize)
674 self.assertEqual(rev.revision, fulltext2)
674 self.assertEqual(rev.revision, fulltext2)
675 self.assertIsNone(rev.delta)
675 self.assertIsNone(rev.delta)
676
676
677 rev = next(gen)
677 rev = next(gen)
678 self.assertEqual(rev.node, node0)
678 self.assertEqual(rev.node, node0)
679 self.assertEqual(rev.p1node, nullid)
679 self.assertEqual(rev.p1node, nullid)
680 self.assertEqual(rev.p2node, nullid)
680 self.assertEqual(rev.p2node, nullid)
681 # Delta behavior is storage dependent, so we can't easily test it.
681 # Delta behavior is storage dependent, so we can't easily test it.
682
682
683 with self.assertRaises(StopIteration):
683 with self.assertRaises(StopIteration):
684 next(gen)
684 next(gen)
685
685
686 # assumehaveparentrevisions=False (the default) won't send a delta for
686 # assumehaveparentrevisions=False (the default) won't send a delta for
687 # the first revision.
687 # the first revision.
688 gen = f.emitrevisions({node2, node1}, revisiondata=True)
688 gen = f.emitrevisions({node2, node1}, revisiondata=True)
689
689
690 rev = next(gen)
690 rev = next(gen)
691 self.assertEqual(rev.node, node1)
691 self.assertEqual(rev.node, node1)
692 self.assertEqual(rev.p1node, node0)
692 self.assertEqual(rev.p1node, node0)
693 self.assertEqual(rev.p2node, nullid)
693 self.assertEqual(rev.p2node, nullid)
694 self.assertEqual(rev.basenode, nullid)
694 self.assertEqual(rev.basenode, nullid)
695 self.assertIsNone(rev.baserevisionsize)
695 self.assertIsNone(rev.baserevisionsize)
696 self.assertEqual(rev.revision, fulltext1)
696 self.assertEqual(rev.revision, fulltext1)
697 self.assertIsNone(rev.delta)
697 self.assertIsNone(rev.delta)
698
698
699 rev = next(gen)
699 rev = next(gen)
700 self.assertEqual(rev.node, node2)
700 self.assertEqual(rev.node, node2)
701 self.assertEqual(rev.p1node, node1)
701 self.assertEqual(rev.p1node, node1)
702 self.assertEqual(rev.p2node, nullid)
702 self.assertEqual(rev.p2node, nullid)
703 self.assertEqual(rev.basenode, node1)
703 self.assertEqual(rev.basenode, node1)
704 self.assertIsNone(rev.baserevisionsize)
704 self.assertIsNone(rev.baserevisionsize)
705 self.assertIsNone(rev.revision)
705 self.assertIsNone(rev.revision)
706 self.assertEqual(rev.delta,
706 self.assertEqual(rev.delta,
707 b'\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x04\x02' +
707 b'\x00\x00\x00\x00\x00\x00\x04\x01\x00\x00\x04\x02' +
708 fulltext2)
708 fulltext2)
709
709
710 with self.assertRaises(StopIteration):
710 with self.assertRaises(StopIteration):
711 next(gen)
711 next(gen)
712
712
713 # assumehaveparentrevisions=True allows delta against initial revision.
713 # assumehaveparentrevisions=True allows delta against initial revision.
714 gen = f.emitrevisions([node2, node1],
714 gen = f.emitrevisions([node2, node1],
715 revisiondata=True, assumehaveparentrevisions=True)
715 revisiondata=True, assumehaveparentrevisions=True)
716
716
717 rev = next(gen)
717 rev = next(gen)
718 self.assertEqual(rev.node, node1)
718 self.assertEqual(rev.node, node1)
719 self.assertEqual(rev.p1node, node0)
719 self.assertEqual(rev.p1node, node0)
720 self.assertEqual(rev.p2node, nullid)
720 self.assertEqual(rev.p2node, nullid)
721 self.assertEqual(rev.basenode, node0)
721 self.assertEqual(rev.basenode, node0)
722 self.assertIsNone(rev.baserevisionsize)
722 self.assertIsNone(rev.baserevisionsize)
723 self.assertIsNone(rev.revision)
723 self.assertIsNone(rev.revision)
724 self.assertEqual(rev.delta,
724 self.assertEqual(rev.delta,
725 b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' +
725 b'\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x01' +
726 fulltext1)
726 fulltext1)
727
727
728 # forceprevious=True forces a delta against the previous revision.
728 # forceprevious=True forces a delta against the previous revision.
729 # Special case for initial revision.
729 # Special case for initial revision.
730 gen = f.emitrevisions([node0], revisiondata=True, deltaprevious=True)
730 gen = f.emitrevisions([node0], revisiondata=True, deltaprevious=True)
731
731
732 rev = next(gen)
732 rev = next(gen)
733 self.assertEqual(rev.node, node0)
733 self.assertEqual(rev.node, node0)
734 self.assertEqual(rev.p1node, nullid)
734 self.assertEqual(rev.p1node, nullid)
735 self.assertEqual(rev.p2node, nullid)
735 self.assertEqual(rev.p2node, nullid)
736 self.assertEqual(rev.basenode, nullid)
736 self.assertEqual(rev.basenode, nullid)
737 self.assertIsNone(rev.baserevisionsize)
737 self.assertIsNone(rev.baserevisionsize)
738 self.assertIsNone(rev.revision)
738 self.assertIsNone(rev.revision)
739 self.assertEqual(rev.delta,
739 self.assertEqual(rev.delta,
740 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00' +
740 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00' +
741 fulltext0)
741 fulltext0)
742
742
743 with self.assertRaises(StopIteration):
743 with self.assertRaises(StopIteration):
744 next(gen)
744 next(gen)
745
745
746 gen = f.emitrevisions([node0, node2], revisiondata=True,
746 gen = f.emitrevisions([node0, node2], revisiondata=True,
747 deltaprevious=True)
747 deltaprevious=True)
748
748
749 rev = next(gen)
749 rev = next(gen)
750 self.assertEqual(rev.node, node0)
750 self.assertEqual(rev.node, node0)
751 self.assertEqual(rev.p1node, nullid)
751 self.assertEqual(rev.p1node, nullid)
752 self.assertEqual(rev.p2node, nullid)
752 self.assertEqual(rev.p2node, nullid)
753 self.assertEqual(rev.basenode, nullid)
753 self.assertEqual(rev.basenode, nullid)
754 self.assertIsNone(rev.baserevisionsize)
754 self.assertIsNone(rev.baserevisionsize)
755 self.assertIsNone(rev.revision)
755 self.assertIsNone(rev.revision)
756 self.assertEqual(rev.delta,
756 self.assertEqual(rev.delta,
757 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00' +
757 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00' +
758 fulltext0)
758 fulltext0)
759
759
760 rev = next(gen)
760 rev = next(gen)
761 self.assertEqual(rev.node, node2)
761 self.assertEqual(rev.node, node2)
762 self.assertEqual(rev.p1node, node1)
762 self.assertEqual(rev.p1node, node1)
763 self.assertEqual(rev.p2node, nullid)
763 self.assertEqual(rev.p2node, nullid)
764 self.assertEqual(rev.basenode, node0)
764 self.assertEqual(rev.basenode, node0)
765
765
766 with self.assertRaises(StopIteration):
766 with self.assertRaises(StopIteration):
767 next(gen)
767 next(gen)
768
768
769 def testrenamed(self):
769 def testrenamed(self):
770 fulltext0 = b'foo'
770 fulltext0 = b'foo'
771 fulltext1 = b'bar'
771 fulltext1 = b'bar'
772 fulltext2 = b'baz'
772 fulltext2 = b'baz'
773
773
774 meta1 = {
774 meta1 = {
775 b'copy': b'source0',
775 b'copy': b'source0',
776 b'copyrev': b'a' * 40,
776 b'copyrev': b'a' * 40,
777 }
777 }
778
778
779 meta2 = {
779 meta2 = {
780 b'copy': b'source1',
780 b'copy': b'source1',
781 b'copyrev': b'b' * 40,
781 b'copyrev': b'b' * 40,
782 }
782 }
783
783
784 stored1 = b''.join([
784 stored1 = b''.join([
785 b'\x01\ncopy: source0\n',
785 b'\x01\ncopy: source0\n',
786 b'copyrev: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n\x01\n',
786 b'copyrev: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n\x01\n',
787 fulltext1,
787 fulltext1,
788 ])
788 ])
789
789
790 stored2 = b''.join([
790 stored2 = b''.join([
791 b'\x01\ncopy: source1\n',
791 b'\x01\ncopy: source1\n',
792 b'copyrev: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n\x01\n',
792 b'copyrev: bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n\x01\n',
793 fulltext2,
793 fulltext2,
794 ])
794 ])
795
795
796 f = self._makefilefn()
796 f = self._makefilefn()
797 with self._maketransactionfn() as tr:
797 with self._maketransactionfn() as tr:
798 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
798 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
799 node1 = f.add(fulltext1, meta1, tr, 1, node0, nullid)
799 node1 = f.add(fulltext1, meta1, tr, 1, node0, nullid)
800 node2 = f.add(fulltext2, meta2, tr, 2, nullid, nullid)
800 node2 = f.add(fulltext2, meta2, tr, 2, nullid, nullid)
801
801
802 # Metadata header isn't recognized when parent isn't nullid.
802 # Metadata header isn't recognized when parent isn't nullid.
803 self.assertEqual(f.size(1), len(stored1))
803 self.assertEqual(f.size(1), len(stored1))
804 self.assertEqual(f.size(2), len(fulltext2))
804 self.assertEqual(f.size(2), len(fulltext2))
805
805
806 self.assertEqual(f.revision(node1), stored1)
806 self.assertEqual(f.revision(node1), stored1)
807 self.assertEqual(f.revision(node1, raw=True), stored1)
807 self.assertEqual(f.revision(node1, raw=True), stored1)
808 self.assertEqual(f.revision(node2), stored2)
808 self.assertEqual(f.revision(node2), stored2)
809 self.assertEqual(f.revision(node2, raw=True), stored2)
809 self.assertEqual(f.revision(node2, raw=True), stored2)
810
810
811 self.assertEqual(f.read(node1), fulltext1)
811 self.assertEqual(f.read(node1), fulltext1)
812 self.assertEqual(f.read(node2), fulltext2)
812 self.assertEqual(f.read(node2), fulltext2)
813
813
814 # Returns False when first parent is set.
814 # Returns False when first parent is set.
815 self.assertFalse(f.renamed(node1))
815 self.assertFalse(f.renamed(node1))
816 self.assertEqual(f.renamed(node2), (b'source1', b'\xbb' * 20))
816 self.assertEqual(f.renamed(node2), (b'source1', b'\xbb' * 20))
817
817
818 self.assertTrue(f.cmp(node1, fulltext1))
818 self.assertTrue(f.cmp(node1, fulltext1))
819 self.assertTrue(f.cmp(node1, stored1))
819 self.assertTrue(f.cmp(node1, stored1))
820 self.assertFalse(f.cmp(node2, fulltext2))
820 self.assertFalse(f.cmp(node2, fulltext2))
821 self.assertTrue(f.cmp(node2, stored2))
821 self.assertTrue(f.cmp(node2, stored2))
822
822
823 def testmetadataprefix(self):
823 def testmetadataprefix(self):
824 # Content with metadata prefix has extra prefix inserted in storage.
824 # Content with metadata prefix has extra prefix inserted in storage.
825 fulltext0 = b'\x01\nfoo'
825 fulltext0 = b'\x01\nfoo'
826 stored0 = b'\x01\n\x01\n\x01\nfoo'
826 stored0 = b'\x01\n\x01\n\x01\nfoo'
827
827
828 fulltext1 = b'\x01\nbar'
828 fulltext1 = b'\x01\nbar'
829 meta1 = {
829 meta1 = {
830 b'copy': b'source0',
830 b'copy': b'source0',
831 b'copyrev': b'b' * 40,
831 b'copyrev': b'b' * 40,
832 }
832 }
833 stored1 = b''.join([
833 stored1 = b''.join([
834 b'\x01\ncopy: source0\n',
834 b'\x01\ncopy: source0\n',
835 b'copyrev: %s\n' % (b'b' * 40),
835 b'copyrev: %s\n' % (b'b' * 40),
836 b'\x01\n\x01\nbar',
836 b'\x01\n\x01\nbar',
837 ])
837 ])
838
838
839 f = self._makefilefn()
839 f = self._makefilefn()
840 with self._maketransactionfn() as tr:
840 with self._maketransactionfn() as tr:
841 node0 = f.add(fulltext0, {}, tr, 0, nullid, nullid)
841 node0 = f.add(fulltext0, {}, tr, 0, nullid, nullid)
842 node1 = f.add(fulltext1, meta1, tr, 1, nullid, nullid)
842 node1 = f.add(fulltext1, meta1, tr, 1, nullid, nullid)
843
843
844 # TODO this is buggy.
844 # TODO this is buggy.
845 self.assertEqual(f.size(0), len(fulltext0) + 4)
845 self.assertEqual(f.size(0), len(fulltext0) + 4)
846
846
847 self.assertEqual(f.size(1), len(fulltext1))
847 self.assertEqual(f.size(1), len(fulltext1))
848
848
849 self.assertEqual(f.revision(node0), stored0)
849 self.assertEqual(f.revision(node0), stored0)
850 self.assertEqual(f.revision(node0, raw=True), stored0)
850 self.assertEqual(f.revision(node0, raw=True), stored0)
851
851
852 self.assertEqual(f.revision(node1), stored1)
852 self.assertEqual(f.revision(node1), stored1)
853 self.assertEqual(f.revision(node1, raw=True), stored1)
853 self.assertEqual(f.revision(node1, raw=True), stored1)
854
854
855 self.assertEqual(f.read(node0), fulltext0)
855 self.assertEqual(f.read(node0), fulltext0)
856 self.assertEqual(f.read(node1), fulltext1)
856 self.assertEqual(f.read(node1), fulltext1)
857
857
858 self.assertFalse(f.cmp(node0, fulltext0))
858 self.assertFalse(f.cmp(node0, fulltext0))
859 self.assertTrue(f.cmp(node0, stored0))
859 self.assertTrue(f.cmp(node0, stored0))
860
860
861 self.assertFalse(f.cmp(node1, fulltext1))
861 self.assertFalse(f.cmp(node1, fulltext1))
862 self.assertTrue(f.cmp(node1, stored0))
862 self.assertTrue(f.cmp(node1, stored0))
863
863
864 def testcensored(self):
864 def testcensored(self):
865 f = self._makefilefn()
865 f = self._makefilefn()
866
866
867 stored1 = storageutil.packmeta({
867 stored1 = storageutil.packmeta({
868 b'censored': b'tombstone',
868 b'censored': b'tombstone',
869 }, b'')
869 }, b'')
870
870
871 # TODO tests are incomplete because we need the node to be
871 # TODO tests are incomplete because we need the node to be
872 # different due to presence of censor metadata. But we can't
872 # different due to presence of censor metadata. But we can't
873 # do this with addrevision().
873 # do this with addrevision().
874 with self._maketransactionfn() as tr:
874 with self._maketransactionfn() as tr:
875 node0 = f.add(b'foo', None, tr, 0, nullid, nullid)
875 node0 = f.add(b'foo', None, tr, 0, nullid, nullid)
876 f.addrevision(stored1, tr, 1, node0, nullid,
876 f.addrevision(stored1, tr, 1, node0, nullid,
877 flags=revlog.REVIDX_ISCENSORED)
877 flags=revlog.REVIDX_ISCENSORED)
878
878
879 self.assertTrue(f.iscensored(1))
879 self.assertTrue(f.iscensored(1))
880
880
881 self.assertEqual(f.revision(1), stored1)
881 self.assertEqual(f.revision(1), stored1)
882 self.assertEqual(f.revision(1, raw=True), stored1)
882 self.assertEqual(f.revision(1, raw=True), stored1)
883
883
884 self.assertEqual(f.read(1), b'')
884 self.assertEqual(f.read(1), b'')
885
885
886 class ifilemutationtests(basetestcase):
886 class ifilemutationtests(basetestcase):
887 """Generic tests for the ifilemutation interface.
887 """Generic tests for the ifilemutation interface.
888
888
889 All file storage backends that support writing should conform to this
889 All file storage backends that support writing should conform to this
890 interface.
890 interface.
891
891
892 Use ``makeifilemutationtests()`` to create an instance of this type.
892 Use ``makeifilemutationtests()`` to create an instance of this type.
893 """
893 """
894 def testaddnoop(self):
894 def testaddnoop(self):
895 f = self._makefilefn()
895 f = self._makefilefn()
896 with self._maketransactionfn() as tr:
896 with self._maketransactionfn() as tr:
897 node0 = f.add(b'foo', None, tr, 0, nullid, nullid)
897 node0 = f.add(b'foo', None, tr, 0, nullid, nullid)
898 node1 = f.add(b'foo', None, tr, 0, nullid, nullid)
898 node1 = f.add(b'foo', None, tr, 0, nullid, nullid)
899 # Varying by linkrev shouldn't impact hash.
899 # Varying by linkrev shouldn't impact hash.
900 node2 = f.add(b'foo', None, tr, 1, nullid, nullid)
900 node2 = f.add(b'foo', None, tr, 1, nullid, nullid)
901
901
902 self.assertEqual(node1, node0)
902 self.assertEqual(node1, node0)
903 self.assertEqual(node2, node0)
903 self.assertEqual(node2, node0)
904 self.assertEqual(len(f), 1)
904 self.assertEqual(len(f), 1)
905
905
906 def testaddrevisionbadnode(self):
906 def testaddrevisionbadnode(self):
907 f = self._makefilefn()
907 f = self._makefilefn()
908 with self._maketransactionfn() as tr:
908 with self._maketransactionfn() as tr:
909 # Adding a revision with bad node value fails.
909 # Adding a revision with bad node value fails.
910 with self.assertRaises(error.StorageError):
910 with self.assertRaises(error.StorageError):
911 f.addrevision(b'foo', tr, 0, nullid, nullid, node=b'\x01' * 20)
911 f.addrevision(b'foo', tr, 0, nullid, nullid, node=b'\x01' * 20)
912
912
913 def testaddrevisionunknownflag(self):
913 def testaddrevisionunknownflag(self):
914 f = self._makefilefn()
914 f = self._makefilefn()
915 with self._maketransactionfn() as tr:
915 with self._maketransactionfn() as tr:
916 for i in range(15, 0, -1):
916 for i in range(15, 0, -1):
917 if (1 << i) & ~revlog.REVIDX_KNOWN_FLAGS:
917 if (1 << i) & ~revlog.REVIDX_KNOWN_FLAGS:
918 flags = 1 << i
918 flags = 1 << i
919 break
919 break
920
920
921 with self.assertRaises(error.StorageError):
921 with self.assertRaises(error.StorageError):
922 f.addrevision(b'foo', tr, 0, nullid, nullid, flags=flags)
922 f.addrevision(b'foo', tr, 0, nullid, nullid, flags=flags)
923
923
924 def testaddgroupsimple(self):
924 def testaddgroupsimple(self):
925 f = self._makefilefn()
925 f = self._makefilefn()
926
926
927 callbackargs = []
927 callbackargs = []
928 def cb(*args, **kwargs):
928 def cb(*args, **kwargs):
929 callbackargs.append((args, kwargs))
929 callbackargs.append((args, kwargs))
930
930
931 def linkmapper(node):
931 def linkmapper(node):
932 return 0
932 return 0
933
933
934 with self._maketransactionfn() as tr:
934 with self._maketransactionfn() as tr:
935 nodes = f.addgroup([], None, tr, addrevisioncb=cb)
935 nodes = f.addgroup([], None, tr, addrevisioncb=cb)
936
936
937 self.assertEqual(nodes, [])
937 self.assertEqual(nodes, [])
938 self.assertEqual(callbackargs, [])
938 self.assertEqual(callbackargs, [])
939 self.assertEqual(len(f), 0)
939 self.assertEqual(len(f), 0)
940
940
941 fulltext0 = b'foo'
941 fulltext0 = b'foo'
942 delta0 = mdiff.trivialdiffheader(len(fulltext0)) + fulltext0
942 delta0 = mdiff.trivialdiffheader(len(fulltext0)) + fulltext0
943
943
944 deltas = [
944 deltas = [
945 (b'\x01' * 20, nullid, nullid, nullid, nullid, delta0, 0),
945 (b'\x01' * 20, nullid, nullid, nullid, nullid, delta0, 0),
946 ]
946 ]
947
947
948 with self._maketransactionfn() as tr:
948 with self._maketransactionfn() as tr:
949 with self.assertRaises(error.StorageError):
949 with self.assertRaises(error.StorageError):
950 f.addgroup(deltas, linkmapper, tr, addrevisioncb=cb)
950 f.addgroup(deltas, linkmapper, tr, addrevisioncb=cb)
951
951
952 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
952 node0 = f.add(fulltext0, None, tr, 0, nullid, nullid)
953
953
954 f = self._makefilefn()
954 f = self._makefilefn()
955
955
956 deltas = [
956 deltas = [
957 (node0, nullid, nullid, nullid, nullid, delta0, 0),
957 (node0, nullid, nullid, nullid, nullid, delta0, 0),
958 ]
958 ]
959
959
960 with self._maketransactionfn() as tr:
960 with self._maketransactionfn() as tr:
961 nodes = f.addgroup(deltas, linkmapper, tr, addrevisioncb=cb)
961 nodes = f.addgroup(deltas, linkmapper, tr, addrevisioncb=cb)
962
962
963 self.assertEqual(nodes, [
963 self.assertEqual(nodes, [
964 b'\x49\xd8\xcb\xb1\x5c\xe2\x57\x92\x04\x47'
964 b'\x49\xd8\xcb\xb1\x5c\xe2\x57\x92\x04\x47'
965 b'\x00\x6b\x46\x97\x8b\x7a\xf9\x80\xa9\x79'])
965 b'\x00\x6b\x46\x97\x8b\x7a\xf9\x80\xa9\x79'])
966
966
967 self.assertEqual(len(callbackargs), 1)
967 self.assertEqual(len(callbackargs), 1)
968 self.assertEqual(callbackargs[0][0][1], nodes[0])
968 self.assertEqual(callbackargs[0][0][1], nodes[0])
969
969
970 self.assertEqual(list(f.revs()), [0])
970 self.assertEqual(list(f.revs()), [0])
971 self.assertEqual(f.rev(nodes[0]), 0)
971 self.assertEqual(f.rev(nodes[0]), 0)
972 self.assertEqual(f.node(0), nodes[0])
972 self.assertEqual(f.node(0), nodes[0])
973
973
974 def testaddgroupmultiple(self):
974 def testaddgroupmultiple(self):
975 f = self._makefilefn()
975 f = self._makefilefn()
976
976
977 fulltexts = [
977 fulltexts = [
978 b'foo',
978 b'foo',
979 b'bar',
979 b'bar',
980 b'x' * 1024,
980 b'x' * 1024,
981 ]
981 ]
982
982
983 nodes = []
983 nodes = []
984 with self._maketransactionfn() as tr:
984 with self._maketransactionfn() as tr:
985 for fulltext in fulltexts:
985 for fulltext in fulltexts:
986 nodes.append(f.add(fulltext, None, tr, 0, nullid, nullid))
986 nodes.append(f.add(fulltext, None, tr, 0, nullid, nullid))
987
987
988 f = self._makefilefn()
988 f = self._makefilefn()
989 deltas = []
989 deltas = []
990 for i, fulltext in enumerate(fulltexts):
990 for i, fulltext in enumerate(fulltexts):
991 delta = mdiff.trivialdiffheader(len(fulltext)) + fulltext
991 delta = mdiff.trivialdiffheader(len(fulltext)) + fulltext
992
992
993 deltas.append((nodes[i], nullid, nullid, nullid, nullid, delta, 0))
993 deltas.append((nodes[i], nullid, nullid, nullid, nullid, delta, 0))
994
994
995 with self._maketransactionfn() as tr:
995 with self._maketransactionfn() as tr:
996 self.assertEqual(f.addgroup(deltas, lambda x: 0, tr), nodes)
996 self.assertEqual(f.addgroup(deltas, lambda x: 0, tr), nodes)
997
997
998 self.assertEqual(len(f), len(deltas))
998 self.assertEqual(len(f), len(deltas))
999 self.assertEqual(list(f.revs()), [0, 1, 2])
999 self.assertEqual(list(f.revs()), [0, 1, 2])
1000 self.assertEqual(f.rev(nodes[0]), 0)
1000 self.assertEqual(f.rev(nodes[0]), 0)
1001 self.assertEqual(f.rev(nodes[1]), 1)
1001 self.assertEqual(f.rev(nodes[1]), 1)
1002 self.assertEqual(f.rev(nodes[2]), 2)
1002 self.assertEqual(f.rev(nodes[2]), 2)
1003 self.assertEqual(f.node(0), nodes[0])
1003 self.assertEqual(f.node(0), nodes[0])
1004 self.assertEqual(f.node(1), nodes[1])
1004 self.assertEqual(f.node(1), nodes[1])
1005 self.assertEqual(f.node(2), nodes[2])
1005 self.assertEqual(f.node(2), nodes[2])
1006
1006
1007 def makeifileindextests(makefilefn, maketransactionfn):
1007 def makeifileindextests(makefilefn, maketransactionfn):
1008 """Create a unittest.TestCase class suitable for testing file storage.
1008 """Create a unittest.TestCase class suitable for testing file storage.
1009
1009
1010 ``makefilefn`` is a callable which receives the test case as an
1010 ``makefilefn`` is a callable which receives the test case as an
1011 argument and returns an object implementing the ``ifilestorage`` interface.
1011 argument and returns an object implementing the ``ifilestorage`` interface.
1012
1012
1013 ``maketransactionfn`` is a callable which receives the test case as an
1013 ``maketransactionfn`` is a callable which receives the test case as an
1014 argument and returns a transaction object.
1014 argument and returns a transaction object.
1015
1015
1016 Returns a type that is a ``unittest.TestCase`` that can be used for
1016 Returns a type that is a ``unittest.TestCase`` that can be used for
1017 testing the object implementing the file storage interface. Simply
1017 testing the object implementing the file storage interface. Simply
1018 assign the returned value to a module-level attribute and a test loader
1018 assign the returned value to a module-level attribute and a test loader
1019 should find and run it automatically.
1019 should find and run it automatically.
1020 """
1020 """
1021 d = {
1021 d = {
1022 r'_makefilefn': makefilefn,
1022 r'_makefilefn': makefilefn,
1023 r'_maketransactionfn': maketransactionfn,
1023 r'_maketransactionfn': maketransactionfn,
1024 }
1024 }
1025 return type(r'ifileindextests', (ifileindextests,), d)
1025 return type(r'ifileindextests', (ifileindextests,), d)
1026
1026
1027 def makeifiledatatests(makefilefn, maketransactionfn):
1027 def makeifiledatatests(makefilefn, maketransactionfn):
1028 d = {
1028 d = {
1029 r'_makefilefn': makefilefn,
1029 r'_makefilefn': makefilefn,
1030 r'_maketransactionfn': maketransactionfn,
1030 r'_maketransactionfn': maketransactionfn,
1031 }
1031 }
1032 return type(r'ifiledatatests', (ifiledatatests,), d)
1032 return type(r'ifiledatatests', (ifiledatatests,), d)
1033
1033
1034 def makeifilemutationtests(makefilefn, maketransactionfn):
1034 def makeifilemutationtests(makefilefn, maketransactionfn):
1035 d = {
1035 d = {
1036 r'_makefilefn': makefilefn,
1036 r'_makefilefn': makefilefn,
1037 r'_maketransactionfn': maketransactionfn,
1037 r'_maketransactionfn': maketransactionfn,
1038 }
1038 }
1039 return type(r'ifilemutationtests', (ifilemutationtests,), d)
1039 return type(r'ifilemutationtests', (ifilemutationtests,), d)
@@ -1,154 +1,157 b''
1 # storageutil.py - Storage functionality agnostic of backend implementation.
1 # storageutil.py - Storage functionality agnostic of backend implementation.
2 #
2 #
3 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import hashlib
10 import hashlib
11 import re
11 import re
12
12
13 from ..i18n import _
13 from ..i18n import _
14 from ..node import (
14 from ..node import (
15 bin,
15 bin,
16 nullid,
16 nullid,
17 )
17 )
18 from .. import (
18 from .. import (
19 error,
19 error,
20 pycompat,
20 pycompat,
21 )
21 )
22
22
23 _nullhash = hashlib.sha1(nullid)
23 _nullhash = hashlib.sha1(nullid)
24
24
25 def hashrevisionsha1(text, p1, p2):
25 def hashrevisionsha1(text, p1, p2):
26 """Compute the SHA-1 for revision data and its parents.
26 """Compute the SHA-1 for revision data and its parents.
27
27
28 This hash combines both the current file contents and its history
28 This hash combines both the current file contents and its history
29 in a manner that makes it easy to distinguish nodes with the same
29 in a manner that makes it easy to distinguish nodes with the same
30 content in the revision graph.
30 content in the revision graph.
31 """
31 """
32 # As of now, if one of the parent node is null, p2 is null
32 # As of now, if one of the parent node is null, p2 is null
33 if p2 == nullid:
33 if p2 == nullid:
34 # deep copy of a hash is faster than creating one
34 # deep copy of a hash is faster than creating one
35 s = _nullhash.copy()
35 s = _nullhash.copy()
36 s.update(p1)
36 s.update(p1)
37 else:
37 else:
38 # none of the parent nodes are nullid
38 # none of the parent nodes are nullid
39 if p1 < p2:
39 if p1 < p2:
40 a = p1
40 a = p1
41 b = p2
41 b = p2
42 else:
42 else:
43 a = p2
43 a = p2
44 b = p1
44 b = p1
45 s = hashlib.sha1(a)
45 s = hashlib.sha1(a)
46 s.update(b)
46 s.update(b)
47 s.update(text)
47 s.update(text)
48 return s.digest()
48 return s.digest()
49
49
50 METADATA_RE = re.compile(b'\x01\n')
50 METADATA_RE = re.compile(b'\x01\n')
51
51
52 def parsemeta(text):
52 def parsemeta(text):
53 """Parse metadata header from revision data.
53 """Parse metadata header from revision data.
54
54
55 Returns a 2-tuple of (metadata, offset), where both can be None if there
55 Returns a 2-tuple of (metadata, offset), where both can be None if there
56 is no metadata.
56 is no metadata.
57 """
57 """
58 # text can be buffer, so we can't use .startswith or .index
58 # text can be buffer, so we can't use .startswith or .index
59 if text[:2] != b'\x01\n':
59 if text[:2] != b'\x01\n':
60 return None, None
60 return None, None
61 s = METADATA_RE.search(text, 2).start()
61 s = METADATA_RE.search(text, 2).start()
62 mtext = text[2:s]
62 mtext = text[2:s]
63 meta = {}
63 meta = {}
64 for l in mtext.splitlines():
64 for l in mtext.splitlines():
65 k, v = l.split(b': ', 1)
65 k, v = l.split(b': ', 1)
66 meta[k] = v
66 meta[k] = v
67 return meta, s + 2
67 return meta, s + 2
68
68
69 def packmeta(meta, text):
69 def packmeta(meta, text):
70 """Add metadata to fulltext to produce revision text."""
70 """Add metadata to fulltext to produce revision text."""
71 keys = sorted(meta)
71 keys = sorted(meta)
72 metatext = b''.join(b'%s: %s\n' % (k, meta[k]) for k in keys)
72 metatext = b''.join(b'%s: %s\n' % (k, meta[k]) for k in keys)
73 return b'\x01\n%s\x01\n%s' % (metatext, text)
73 return b'\x01\n%s\x01\n%s' % (metatext, text)
74
74
75 def iscensoredtext(text):
75 def iscensoredtext(text):
76 meta = parsemeta(text)[0]
76 meta = parsemeta(text)[0]
77 return meta and b'censored' in meta
77 return meta and b'censored' in meta
78
78
79 def filtermetadata(text):
79 def filtermetadata(text):
80 """Extract just the revision data from source text.
80 """Extract just the revision data from source text.
81
81
82 Returns ``text`` unless it has a metadata header, in which case we return
82 Returns ``text`` unless it has a metadata header, in which case we return
83 a new buffer without hte metadata.
83 a new buffer without hte metadata.
84 """
84 """
85 if not text.startswith(b'\x01\n'):
85 if not text.startswith(b'\x01\n'):
86 return text
86 return text
87
87
88 offset = text.index(b'\x01\n', 2)
88 offset = text.index(b'\x01\n', 2)
89 return text[offset + 2:]
89 return text[offset + 2:]
90
90
91 def iterrevs(storelen, start=0, stop=None):
91 def iterrevs(storelen, start=0, stop=None):
92 """Iterate over revision numbers in a store."""
92 """Iterate over revision numbers in a store."""
93 step = 1
93 step = 1
94
94
95 if stop is not None:
95 if stop is not None:
96 if start > stop:
96 if start > stop:
97 step = -1
97 step = -1
98 stop += step
98 stop += step
99 if stop > storelen:
99 if stop > storelen:
100 stop = storelen
100 stop = storelen
101 else:
101 else:
102 stop = storelen
102 stop = storelen
103
103
104 return pycompat.xrange(start, stop, step)
104 return pycompat.xrange(start, stop, step)
105
105
106 def fileidlookup(store, fileid, identifier):
106 def fileidlookup(store, fileid, identifier):
107 """Resolve the file node for a value.
107 """Resolve the file node for a value.
108
108
109 ``store`` is an object implementing the ``ifileindex`` interface.
109 ``store`` is an object implementing the ``ifileindex`` interface.
110
110
111 ``fileid`` can be:
111 ``fileid`` can be:
112
112
113 * A 20 byte binary node.
113 * A 20 byte binary node.
114 * An integer revision number
114 * An integer revision number
115 * A 40 byte hex node.
115 * A 40 byte hex node.
116 * A bytes that can be parsed as an integer representing a revision number.
116 * A bytes that can be parsed as an integer representing a revision number.
117
117
118 ``identifier`` is used to populate ``error.LookupError`` with an identifier
118 ``identifier`` is used to populate ``error.LookupError`` with an identifier
119 for the store.
119 for the store.
120
120
121 Raises ``error.LookupError`` on failure.
121 Raises ``error.LookupError`` on failure.
122 """
122 """
123 if isinstance(fileid, int):
123 if isinstance(fileid, int):
124 return store.node(fileid)
124 try:
125 return store.node(fileid)
126 except IndexError:
127 raise error.LookupError(fileid, identifier, _('no match found'))
125
128
126 if len(fileid) == 20:
129 if len(fileid) == 20:
127 try:
130 try:
128 store.rev(fileid)
131 store.rev(fileid)
129 return fileid
132 return fileid
130 except error.LookupError:
133 except error.LookupError:
131 pass
134 pass
132
135
133 if len(fileid) == 40:
136 if len(fileid) == 40:
134 try:
137 try:
135 rawnode = bin(fileid)
138 rawnode = bin(fileid)
136 store.rev(rawnode)
139 store.rev(rawnode)
137 return rawnode
140 return rawnode
138 except TypeError:
141 except TypeError:
139 pass
142 pass
140
143
141 try:
144 try:
142 rev = int(fileid)
145 rev = int(fileid)
143
146
144 if b'%d' % rev != fileid:
147 if b'%d' % rev != fileid:
145 raise ValueError
148 raise ValueError
146
149
147 try:
150 try:
148 return store.node(rev)
151 return store.node(rev)
149 except (IndexError, TypeError):
152 except (IndexError, TypeError):
150 pass
153 pass
151 except (ValueError, OverflowError):
154 except (ValueError, OverflowError):
152 pass
155 pass
153
156
154 raise error.LookupError(fileid, identifier, _('no match found'))
157 raise error.LookupError(fileid, identifier, _('no match found'))
General Comments 0
You need to be logged in to leave comments. Login now