##// END OF EJS Templates
test-manifest: create constant for empty manifest...
Martin von Zweigbergk -
r24569:5491248e default
parent child Browse files
Show More
@@ -1,389 +1,391 b''
1 1 import binascii
2 2 import unittest
3 3 import itertools
4 4
5 5 import silenttestrunner
6 6
7 7 from mercurial import manifest as manifestmod
8 8 from mercurial import match as matchmod
9 9
10 EMTPY_MANIFEST = ''
11
10 12 HASH_1 = '1' * 40
11 13 HASH_2 = 'f' * 40
12 14 HASH_3 = '1234567890abcdef0987654321deadbeef0fcafe'
13 15 A_SHORT_MANIFEST = (
14 16 'bar/baz/qux.py\0%(hash2)s%(flag2)s\n'
15 17 'foo\0%(hash1)s%(flag1)s\n'
16 18 ) % {'hash1': HASH_1,
17 19 'flag1': '',
18 20 'hash2': HASH_2,
19 21 'flag2': 'l',
20 22 }
21 23
22 24 A_DEEPER_MANIFEST = (
23 25 'a/b/c/bar.py\0%(hash3)s%(flag1)s\n'
24 26 'a/b/c/bar.txt\0%(hash1)s%(flag1)s\n'
25 27 'a/b/c/foo.py\0%(hash3)s%(flag1)s\n'
26 28 'a/b/c/foo.txt\0%(hash2)s%(flag2)s\n'
27 29 'a/b/d/baz.py\0%(hash3)s%(flag1)s\n'
28 30 'a/b/d/qux.py\0%(hash1)s%(flag2)s\n'
29 31 'a/b/d/ten.txt\0%(hash3)s%(flag2)s\n'
30 32 'a/b/dog.py\0%(hash3)s%(flag1)s\n'
31 33 'a/b/fish.py\0%(hash2)s%(flag1)s\n'
32 34 'a/c/london.py\0%(hash3)s%(flag2)s\n'
33 35 'a/c/paper.txt\0%(hash2)s%(flag2)s\n'
34 36 'a/c/paris.py\0%(hash2)s%(flag1)s\n'
35 37 'a/d/apple.py\0%(hash3)s%(flag1)s\n'
36 38 'a/d/pizza.py\0%(hash3)s%(flag2)s\n'
37 39 'a/green.py\0%(hash1)s%(flag2)s\n'
38 40 'a/purple.py\0%(hash2)s%(flag1)s\n'
39 41 'app.py\0%(hash3)s%(flag1)s\n'
40 42 'readme.txt\0%(hash2)s%(flag1)s\n'
41 43 ) % {'hash1': HASH_1,
42 44 'flag1': '',
43 45 'hash2': HASH_2,
44 46 'flag2': 'l',
45 47 'hash3': HASH_3,
46 48 }
47 49
48 50 HUGE_MANIFEST_ENTRIES = 200001
49 51
50 52 A_HUGE_MANIFEST = ''.join(sorted(
51 53 'file%d\0%s%s\n' % (i, h, f) for i, h, f in
52 54 itertools.izip(xrange(200001),
53 55 itertools.cycle((HASH_1, HASH_2)),
54 56 itertools.cycle(('', 'x', 'l')))))
55 57
56 58 def parsemanifest(text):
57 59 return manifestmod.manifestdict(text)
58 60
59 61 class testmanifest(unittest.TestCase):
60 62
61 63 def assertIn(self, thing, container, msg=None):
62 64 # assertIn new in 2.7, use it if available, otherwise polyfill
63 65 sup = getattr(unittest.TestCase, 'assertIn', False)
64 66 if sup:
65 67 return sup(self, thing, container, msg=msg)
66 68 if not msg:
67 69 msg = 'Expected %r in %r' % (thing, container)
68 70 self.assert_(thing in container, msg)
69 71
70 72 def testEmptyManifest(self):
71 m = parsemanifest('')
73 m = parsemanifest(EMTPY_MANIFEST)
72 74 self.assertEqual(0, len(m))
73 75 self.assertEqual([], list(m))
74 76
75 77 def testManifest(self):
76 78 m = parsemanifest(A_SHORT_MANIFEST)
77 79 self.assertEqual(['bar/baz/qux.py', 'foo'], list(m))
78 80 self.assertEqual(binascii.unhexlify(HASH_2), m['bar/baz/qux.py'])
79 81 self.assertEqual('l', m.flags('bar/baz/qux.py'))
80 82 self.assertEqual(binascii.unhexlify(HASH_1), m['foo'])
81 83 self.assertEqual('', m.flags('foo'))
82 84 self.assertRaises(KeyError, lambda : m['wat'])
83 85
84 86 def testSetItem(self):
85 87 want = binascii.unhexlify(HASH_1)
86 88
87 m = parsemanifest('')
89 m = parsemanifest(EMTPY_MANIFEST)
88 90 m['a'] = want
89 91 self.assertIn('a', m)
90 92 self.assertEqual(want, m['a'])
91 93 self.assertEqual('a\0' + HASH_1 + '\n', m.text())
92 94
93 95 m = parsemanifest(A_SHORT_MANIFEST)
94 96 m['a'] = want
95 97 self.assertEqual(want, m['a'])
96 98 self.assertEqual('a\0' + HASH_1 + '\n' + A_SHORT_MANIFEST,
97 99 m.text())
98 100
99 101 def testSetFlag(self):
100 102 want = 'x'
101 103
102 m = parsemanifest('')
104 m = parsemanifest(EMTPY_MANIFEST)
103 105 # first add a file; a file-less flag makes no sense
104 106 m['a'] = binascii.unhexlify(HASH_1)
105 107 m.setflag('a', want)
106 108 self.assertEqual(want, m.flags('a'))
107 109 self.assertEqual('a\0' + HASH_1 + want + '\n', m.text())
108 110
109 111 m = parsemanifest(A_SHORT_MANIFEST)
110 112 # first add a file; a file-less flag makes no sense
111 113 m['a'] = binascii.unhexlify(HASH_1)
112 114 m.setflag('a', want)
113 115 self.assertEqual(want, m.flags('a'))
114 116 self.assertEqual('a\0' + HASH_1 + want + '\n' + A_SHORT_MANIFEST,
115 117 m.text())
116 118
117 119 def testCopy(self):
118 120 m = parsemanifest(A_SHORT_MANIFEST)
119 121 m['a'] = binascii.unhexlify(HASH_1)
120 122 m2 = m.copy()
121 123 del m
122 124 del m2 # make sure we don't double free() anything
123 125
124 126 def testCompaction(self):
125 127 unhex = binascii.unhexlify
126 128 h1, h2 = unhex(HASH_1), unhex(HASH_2)
127 129 m = parsemanifest(A_SHORT_MANIFEST)
128 130 m['alpha'] = h1
129 131 m['beta'] = h2
130 132 del m['foo']
131 133 want = 'alpha\0%s\nbar/baz/qux.py\0%sl\nbeta\0%s\n' % (
132 134 HASH_1, HASH_2, HASH_2)
133 135 self.assertEqual(want, m.text())
134 136 self.assertEqual(3, len(m))
135 137 self.assertEqual(['alpha', 'bar/baz/qux.py', 'beta'], list(m))
136 138 self.assertEqual(h1, m['alpha'])
137 139 self.assertEqual(h2, m['bar/baz/qux.py'])
138 140 self.assertEqual(h2, m['beta'])
139 141 self.assertEqual('', m.flags('alpha'))
140 142 self.assertEqual('l', m.flags('bar/baz/qux.py'))
141 143 self.assertEqual('', m.flags('beta'))
142 144 self.assertRaises(KeyError, lambda : m['foo'])
143 145
144 146 def testSetGetNodeSuffix(self):
145 147 clean = parsemanifest(A_SHORT_MANIFEST)
146 148 m = parsemanifest(A_SHORT_MANIFEST)
147 149 h = m['foo']
148 150 f = m.flags('foo')
149 151 want = h + 'a'
150 152 # Merge code wants to set 21-byte fake hashes at times
151 153 m['foo'] = want
152 154 self.assertEqual(want, m['foo'])
153 155 self.assertEqual([('bar/baz/qux.py', binascii.unhexlify(HASH_2)),
154 156 ('foo', binascii.unhexlify(HASH_1) + 'a')],
155 157 list(m.iteritems()))
156 158 # Sometimes it even tries a 22-byte fake hash, but we can
157 159 # return 21 and it'll work out
158 160 m['foo'] = want + '+'
159 161 self.assertEqual(want, m['foo'])
160 162 # make sure the suffix survives a copy
161 163 match = matchmod.match('', '', ['re:foo'])
162 164 m2 = m.matches(match)
163 165 self.assertEqual(want, m2['foo'])
164 166 self.assertEqual(1, len(m2))
165 167 m2 = m.copy()
166 168 self.assertEqual(want, m2['foo'])
167 169 # suffix with iteration
168 170 self.assertEqual([('bar/baz/qux.py', binascii.unhexlify(HASH_2)),
169 171 ('foo', want)],
170 172 list(m.iteritems()))
171 173
172 174 # shows up in diff
173 175 self.assertEqual({'foo': ((want, f), (h, ''))}, m.diff(clean))
174 176 self.assertEqual({'foo': ((h, ''), (want, f))}, clean.diff(m))
175 177
176 178 def testMatchException(self):
177 179 m = parsemanifest(A_SHORT_MANIFEST)
178 180 match = matchmod.match('', '', ['re:.*'])
179 181 def filt(path):
180 182 if path == 'foo':
181 183 assert False
182 184 return True
183 185 match.matchfn = filt
184 186 self.assertRaises(AssertionError, m.matches, match)
185 187
186 188 def testRemoveItem(self):
187 189 m = parsemanifest(A_SHORT_MANIFEST)
188 190 del m['foo']
189 191 self.assertRaises(KeyError, lambda : m['foo'])
190 192 self.assertEqual(1, len(m))
191 193 self.assertEqual(1, len(list(m)))
192 194 # now restore and make sure everything works right
193 195 m['foo'] = 'a' * 20
194 196 self.assertEqual(2, len(m))
195 197 self.assertEqual(2, len(list(m)))
196 198
197 199 def testManifestDiff(self):
198 200 MISSING = (None, '')
199 201 addl = 'z-only-in-left\0' + HASH_1 + '\n'
200 202 addr = 'z-only-in-right\0' + HASH_2 + 'x\n'
201 203 left = parsemanifest(
202 204 A_SHORT_MANIFEST.replace(HASH_1, HASH_3 + 'x') + addl)
203 205 right = parsemanifest(A_SHORT_MANIFEST + addr)
204 206 want = {
205 207 'foo': ((binascii.unhexlify(HASH_3), 'x'),
206 208 (binascii.unhexlify(HASH_1), '')),
207 209 'z-only-in-left': ((binascii.unhexlify(HASH_1), ''), MISSING),
208 210 'z-only-in-right': (MISSING, (binascii.unhexlify(HASH_2), 'x')),
209 211 }
210 212 self.assertEqual(want, left.diff(right))
211 213
212 214 want = {
213 215 'bar/baz/qux.py': (MISSING, (binascii.unhexlify(HASH_2), 'l')),
214 216 'foo': (MISSING, (binascii.unhexlify(HASH_3), 'x')),
215 217 'z-only-in-left': (MISSING, (binascii.unhexlify(HASH_1), '')),
216 218 }
217 self.assertEqual(want, parsemanifest('').diff(left))
219 self.assertEqual(want, parsemanifest(EMTPY_MANIFEST).diff(left))
218 220
219 221 want = {
220 222 'bar/baz/qux.py': ((binascii.unhexlify(HASH_2), 'l'), MISSING),
221 223 'foo': ((binascii.unhexlify(HASH_3), 'x'), MISSING),
222 224 'z-only-in-left': ((binascii.unhexlify(HASH_1), ''), MISSING),
223 225 }
224 self.assertEqual(want, left.diff(parsemanifest('')))
226 self.assertEqual(want, left.diff(parsemanifest(EMTPY_MANIFEST)))
225 227 copy = right.copy()
226 228 del copy['z-only-in-right']
227 229 del right['foo']
228 230 want = {
229 231 'foo': (MISSING, (binascii.unhexlify(HASH_1), '')),
230 232 'z-only-in-right': ((binascii.unhexlify(HASH_2), 'x'), MISSING),
231 233 }
232 234 self.assertEqual(want, right.diff(copy))
233 235
234 236 short = parsemanifest(A_SHORT_MANIFEST)
235 237 pruned = short.copy()
236 238 del pruned['foo']
237 239 want = {
238 240 'foo': ((binascii.unhexlify(HASH_1), ''), MISSING),
239 241 }
240 242 self.assertEqual(want, short.diff(pruned))
241 243 want = {
242 244 'foo': (MISSING, (binascii.unhexlify(HASH_1), '')),
243 245 }
244 246 self.assertEqual(want, pruned.diff(short))
245 247 want = {
246 248 'bar/baz/qux.py': None,
247 249 'foo': (MISSING, (binascii.unhexlify(HASH_1), '')),
248 250 }
249 251 self.assertEqual(want, pruned.diff(short, True))
250 252
251 253 def testReversedLines(self):
252 254 backwards = ''.join(
253 255 l + '\n' for l in reversed(A_SHORT_MANIFEST.split('\n')) if l)
254 256 try:
255 257 parsemanifest(backwards)
256 258 self.fail('Should have raised ValueError')
257 259 except ValueError, v:
258 260 self.assertIn('Manifest lines not in sorted order.', str(v))
259 261
260 262 def testNoTerminalNewline(self):
261 263 try:
262 264 parsemanifest(A_SHORT_MANIFEST + 'wat')
263 265 self.fail('Should have raised ValueError')
264 266 except ValueError, v:
265 267 self.assertIn('Manifest did not end in a newline.', str(v))
266 268
267 269 def testNoNewLineAtAll(self):
268 270 try:
269 271 parsemanifest('wat')
270 272 self.fail('Should have raised ValueError')
271 273 except ValueError, v:
272 274 self.assertIn('Manifest did not end in a newline.', str(v))
273 275
274 276 def testHugeManifest(self):
275 277 m = parsemanifest(A_HUGE_MANIFEST)
276 278 self.assertEqual(HUGE_MANIFEST_ENTRIES, len(m))
277 279 self.assertEqual(len(m), len(list(m)))
278 280
279 281 def testMatchesMetadata(self):
280 282 '''Tests matches() for a few specific files to make sure that both
281 283 the set of files as well as their flags and nodeids are correct in
282 284 the resulting manifest.'''
283 285 m = parsemanifest(A_HUGE_MANIFEST)
284 286
285 287 match = matchmod.match('/', '',
286 288 ['file1', 'file200', 'file300'], exact=True)
287 289 m2 = m.matches(match)
288 290
289 291 w = ('file1\0%sx\n'
290 292 'file200\0%sl\n'
291 293 'file300\0%s\n') % (HASH_2, HASH_1, HASH_1)
292 294 self.assertEqual(w, m2.text())
293 295
294 296 def testMatchesNonexistentFile(self):
295 297 '''Tests matches() for a small set of specific files, including one
296 298 nonexistent file to make sure in only matches against existing files.
297 299 '''
298 300 m = parsemanifest(A_DEEPER_MANIFEST)
299 301
300 302 match = matchmod.match('/', '',
301 303 ['a/b/c/bar.txt', 'a/b/d/qux.py', 'readme.txt', 'nonexistent'],
302 304 exact=True)
303 305 m2 = m.matches(match)
304 306
305 307 self.assertEqual(
306 308 ['a/b/c/bar.txt', 'a/b/d/qux.py', 'readme.txt'],
307 309 m2.keys())
308 310
309 311 def testMatchesNonexistentDirectory(self):
310 312 '''Tests matches() for a relpath match on a directory that doesn't
311 313 actually exist.'''
312 314 m = parsemanifest(A_DEEPER_MANIFEST)
313 315
314 316 match = matchmod.match('/', '', ['a/f'], default='relpath')
315 317 m2 = m.matches(match)
316 318
317 319 self.assertEqual([], m2.keys())
318 320
319 321 def testMatchesExactLarge(self):
320 322 '''Tests matches() for files matching a large list of exact files.
321 323 '''
322 324 m = parsemanifest(A_HUGE_MANIFEST)
323 325
324 326 flist = m.keys()[80:300]
325 327 match = matchmod.match('/', '', flist, exact=True)
326 328 m2 = m.matches(match)
327 329
328 330 self.assertEqual(flist, m2.keys())
329 331
330 332 def testMatchesFull(self):
331 333 '''Tests matches() for what should be a full match.'''
332 334 m = parsemanifest(A_DEEPER_MANIFEST)
333 335
334 336 match = matchmod.match('/', '', [''])
335 337 m2 = m.matches(match)
336 338
337 339 self.assertEqual(m.keys(), m2.keys())
338 340
339 341 def testMatchesDirectory(self):
340 342 '''Tests matches() on a relpath match on a directory, which should
341 343 match against all files within said directory.'''
342 344 m = parsemanifest(A_DEEPER_MANIFEST)
343 345
344 346 match = matchmod.match('/', '', ['a/b'], default='relpath')
345 347 m2 = m.matches(match)
346 348
347 349 self.assertEqual([
348 350 'a/b/c/bar.py', 'a/b/c/bar.txt', 'a/b/c/foo.py', 'a/b/c/foo.txt',
349 351 'a/b/d/baz.py', 'a/b/d/qux.py', 'a/b/d/ten.txt', 'a/b/dog.py',
350 352 'a/b/fish.py'], m2.keys())
351 353
352 354 def testMatchesExactPath(self):
353 355 '''Tests matches() on an exact match on a directory, which should
354 356 result in an empty manifest because you can't perform an exact match
355 357 against a directory.'''
356 358 m = parsemanifest(A_DEEPER_MANIFEST)
357 359
358 360 match = matchmod.match('/', '', ['a/b'], exact=True)
359 361 m2 = m.matches(match)
360 362
361 363 self.assertEqual([], m2.keys())
362 364
363 365 def testMatchesCwd(self):
364 366 '''Tests matches() on a relpath match with the current directory ('.')
365 367 when not in the root directory.'''
366 368 m = parsemanifest(A_DEEPER_MANIFEST)
367 369
368 370 match = matchmod.match('/', 'a/b', ['.'], default='relpath')
369 371 m2 = m.matches(match)
370 372
371 373 self.assertEqual([
372 374 'a/b/c/bar.py', 'a/b/c/bar.txt', 'a/b/c/foo.py', 'a/b/c/foo.txt',
373 375 'a/b/d/baz.py', 'a/b/d/qux.py', 'a/b/d/ten.txt', 'a/b/dog.py',
374 376 'a/b/fish.py'], m2.keys())
375 377
376 378 def testMatchesWithPattern(self):
377 379 '''Tests matches() for files matching a pattern that reside
378 380 deeper than the specified directory.'''
379 381 m = parsemanifest(A_DEEPER_MANIFEST)
380 382
381 383 match = matchmod.match('/', '', ['a/b/*/*.txt'])
382 384 m2 = m.matches(match)
383 385
384 386 self.assertEqual(
385 387 ['a/b/c/bar.txt', 'a/b/c/foo.txt', 'a/b/d/ten.txt'],
386 388 m2.keys())
387 389
388 390 if __name__ == '__main__':
389 391 silenttestrunner.main(__name__)
General Comments 0
You need to be logged in to leave comments. Login now