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