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