##// END OF EJS Templates
py3: use `zip()` instead of trying to use `itertools.izip()`
Manuel Jacob -
r50182:7fe82a51 default
parent child Browse files
Show More
@@ -1,460 +1,458 b''
1 import binascii
1 import binascii
2 import itertools
2 import itertools
3 import silenttestrunner
3 import silenttestrunner
4 import unittest
4 import unittest
5 import zlib
5 import zlib
6
6
7 from mercurial.node import sha1nodeconstants
7 from mercurial.node import sha1nodeconstants
8
8
9 from mercurial import (
9 from mercurial import (
10 manifest as manifestmod,
10 manifest as manifestmod,
11 match as matchmod,
11 match as matchmod,
12 util,
12 util,
13 )
13 )
14
14
15 EMTPY_MANIFEST = b''
15 EMTPY_MANIFEST = b''
16
16
17 HASH_1 = b'1' * 40
17 HASH_1 = b'1' * 40
18 BIN_HASH_1 = binascii.unhexlify(HASH_1)
18 BIN_HASH_1 = binascii.unhexlify(HASH_1)
19 HASH_2 = b'f' * 40
19 HASH_2 = b'f' * 40
20 BIN_HASH_2 = binascii.unhexlify(HASH_2)
20 BIN_HASH_2 = binascii.unhexlify(HASH_2)
21 HASH_3 = b'1234567890abcdef0987654321deadbeef0fcafe'
21 HASH_3 = b'1234567890abcdef0987654321deadbeef0fcafe'
22 BIN_HASH_3 = binascii.unhexlify(HASH_3)
22 BIN_HASH_3 = binascii.unhexlify(HASH_3)
23 A_SHORT_MANIFEST = (
23 A_SHORT_MANIFEST = (
24 b'bar/baz/qux.py\0%(hash2)s%(flag2)s\n' b'foo\0%(hash1)s%(flag1)s\n'
24 b'bar/baz/qux.py\0%(hash2)s%(flag2)s\n' b'foo\0%(hash1)s%(flag1)s\n'
25 ) % {
25 ) % {
26 b'hash1': HASH_1,
26 b'hash1': HASH_1,
27 b'flag1': b'',
27 b'flag1': b'',
28 b'hash2': HASH_2,
28 b'hash2': HASH_2,
29 b'flag2': b'l',
29 b'flag2': b'l',
30 }
30 }
31
31
32 A_DEEPER_MANIFEST = (
32 A_DEEPER_MANIFEST = (
33 b'a/b/c/bar.py\0%(hash3)s%(flag1)s\n'
33 b'a/b/c/bar.py\0%(hash3)s%(flag1)s\n'
34 b'a/b/c/bar.txt\0%(hash1)s%(flag1)s\n'
34 b'a/b/c/bar.txt\0%(hash1)s%(flag1)s\n'
35 b'a/b/c/foo.py\0%(hash3)s%(flag1)s\n'
35 b'a/b/c/foo.py\0%(hash3)s%(flag1)s\n'
36 b'a/b/c/foo.txt\0%(hash2)s%(flag2)s\n'
36 b'a/b/c/foo.txt\0%(hash2)s%(flag2)s\n'
37 b'a/b/d/baz.py\0%(hash3)s%(flag1)s\n'
37 b'a/b/d/baz.py\0%(hash3)s%(flag1)s\n'
38 b'a/b/d/qux.py\0%(hash1)s%(flag2)s\n'
38 b'a/b/d/qux.py\0%(hash1)s%(flag2)s\n'
39 b'a/b/d/ten.txt\0%(hash3)s%(flag2)s\n'
39 b'a/b/d/ten.txt\0%(hash3)s%(flag2)s\n'
40 b'a/b/dog.py\0%(hash3)s%(flag1)s\n'
40 b'a/b/dog.py\0%(hash3)s%(flag1)s\n'
41 b'a/b/fish.py\0%(hash2)s%(flag1)s\n'
41 b'a/b/fish.py\0%(hash2)s%(flag1)s\n'
42 b'a/c/london.py\0%(hash3)s%(flag2)s\n'
42 b'a/c/london.py\0%(hash3)s%(flag2)s\n'
43 b'a/c/paper.txt\0%(hash2)s%(flag2)s\n'
43 b'a/c/paper.txt\0%(hash2)s%(flag2)s\n'
44 b'a/c/paris.py\0%(hash2)s%(flag1)s\n'
44 b'a/c/paris.py\0%(hash2)s%(flag1)s\n'
45 b'a/d/apple.py\0%(hash3)s%(flag1)s\n'
45 b'a/d/apple.py\0%(hash3)s%(flag1)s\n'
46 b'a/d/pizza.py\0%(hash3)s%(flag2)s\n'
46 b'a/d/pizza.py\0%(hash3)s%(flag2)s\n'
47 b'a/green.py\0%(hash1)s%(flag2)s\n'
47 b'a/green.py\0%(hash1)s%(flag2)s\n'
48 b'a/purple.py\0%(hash2)s%(flag1)s\n'
48 b'a/purple.py\0%(hash2)s%(flag1)s\n'
49 b'app.py\0%(hash3)s%(flag1)s\n'
49 b'app.py\0%(hash3)s%(flag1)s\n'
50 b'readme.txt\0%(hash2)s%(flag1)s\n'
50 b'readme.txt\0%(hash2)s%(flag1)s\n'
51 ) % {
51 ) % {
52 b'hash1': HASH_1,
52 b'hash1': HASH_1,
53 b'flag1': b'',
53 b'flag1': b'',
54 b'hash2': HASH_2,
54 b'hash2': HASH_2,
55 b'flag2': b'l',
55 b'flag2': b'l',
56 b'hash3': HASH_3,
56 b'hash3': HASH_3,
57 }
57 }
58
58
59 HUGE_MANIFEST_ENTRIES = 200001
59 HUGE_MANIFEST_ENTRIES = 200001
60
60
61 izip = getattr(itertools, 'izip', zip)
62
63 A_HUGE_MANIFEST = b''.join(
61 A_HUGE_MANIFEST = b''.join(
64 sorted(
62 sorted(
65 b'file%d\0%s%s\n' % (i, h, f)
63 b'file%d\0%s%s\n' % (i, h, f)
66 for i, h, f in izip(
64 for i, h, f in zip(
67 range(200001),
65 range(200001),
68 itertools.cycle((HASH_1, HASH_2)),
66 itertools.cycle((HASH_1, HASH_2)),
69 itertools.cycle((b'', b'x', b'l')),
67 itertools.cycle((b'', b'x', b'l')),
70 )
68 )
71 )
69 )
72 )
70 )
73
71
74
72
75 class basemanifesttests:
73 class basemanifesttests:
76 def parsemanifest(self, text):
74 def parsemanifest(self, text):
77 raise NotImplementedError('parsemanifest not implemented by test case')
75 raise NotImplementedError('parsemanifest not implemented by test case')
78
76
79 def testEmptyManifest(self):
77 def testEmptyManifest(self):
80 m = self.parsemanifest(20, EMTPY_MANIFEST)
78 m = self.parsemanifest(20, EMTPY_MANIFEST)
81 self.assertEqual(0, len(m))
79 self.assertEqual(0, len(m))
82 self.assertEqual([], list(m))
80 self.assertEqual([], list(m))
83
81
84 def testManifest(self):
82 def testManifest(self):
85 m = self.parsemanifest(20, A_SHORT_MANIFEST)
83 m = self.parsemanifest(20, A_SHORT_MANIFEST)
86 self.assertEqual([b'bar/baz/qux.py', b'foo'], list(m))
84 self.assertEqual([b'bar/baz/qux.py', b'foo'], list(m))
87 self.assertEqual(BIN_HASH_2, m[b'bar/baz/qux.py'])
85 self.assertEqual(BIN_HASH_2, m[b'bar/baz/qux.py'])
88 self.assertEqual(b'l', m.flags(b'bar/baz/qux.py'))
86 self.assertEqual(b'l', m.flags(b'bar/baz/qux.py'))
89 self.assertEqual(BIN_HASH_1, m[b'foo'])
87 self.assertEqual(BIN_HASH_1, m[b'foo'])
90 self.assertEqual(b'', m.flags(b'foo'))
88 self.assertEqual(b'', m.flags(b'foo'))
91 with self.assertRaises(KeyError):
89 with self.assertRaises(KeyError):
92 m[b'wat']
90 m[b'wat']
93
91
94 def testSetItem(self):
92 def testSetItem(self):
95 want = BIN_HASH_1
93 want = BIN_HASH_1
96
94
97 m = self.parsemanifest(20, EMTPY_MANIFEST)
95 m = self.parsemanifest(20, EMTPY_MANIFEST)
98 m[b'a'] = want
96 m[b'a'] = want
99 self.assertIn(b'a', m)
97 self.assertIn(b'a', m)
100 self.assertEqual(want, m[b'a'])
98 self.assertEqual(want, m[b'a'])
101 self.assertEqual(b'a\0' + HASH_1 + b'\n', m.text())
99 self.assertEqual(b'a\0' + HASH_1 + b'\n', m.text())
102
100
103 m = self.parsemanifest(20, A_SHORT_MANIFEST)
101 m = self.parsemanifest(20, A_SHORT_MANIFEST)
104 m[b'a'] = want
102 m[b'a'] = want
105 self.assertEqual(want, m[b'a'])
103 self.assertEqual(want, m[b'a'])
106 self.assertEqual(b'a\0' + HASH_1 + b'\n' + A_SHORT_MANIFEST, m.text())
104 self.assertEqual(b'a\0' + HASH_1 + b'\n' + A_SHORT_MANIFEST, m.text())
107
105
108 def testSetFlag(self):
106 def testSetFlag(self):
109 want = b'x'
107 want = b'x'
110
108
111 m = self.parsemanifest(20, EMTPY_MANIFEST)
109 m = self.parsemanifest(20, EMTPY_MANIFEST)
112 # first add a file; a file-less flag makes no sense
110 # first add a file; a file-less flag makes no sense
113 m[b'a'] = BIN_HASH_1
111 m[b'a'] = BIN_HASH_1
114 m.setflag(b'a', want)
112 m.setflag(b'a', want)
115 self.assertEqual(want, m.flags(b'a'))
113 self.assertEqual(want, m.flags(b'a'))
116 self.assertEqual(b'a\0' + HASH_1 + want + b'\n', m.text())
114 self.assertEqual(b'a\0' + HASH_1 + want + b'\n', m.text())
117
115
118 m = self.parsemanifest(20, A_SHORT_MANIFEST)
116 m = self.parsemanifest(20, A_SHORT_MANIFEST)
119 # first add a file; a file-less flag makes no sense
117 # first add a file; a file-less flag makes no sense
120 m[b'a'] = BIN_HASH_1
118 m[b'a'] = BIN_HASH_1
121 m.setflag(b'a', want)
119 m.setflag(b'a', want)
122 self.assertEqual(want, m.flags(b'a'))
120 self.assertEqual(want, m.flags(b'a'))
123 self.assertEqual(
121 self.assertEqual(
124 b'a\0' + HASH_1 + want + b'\n' + A_SHORT_MANIFEST, m.text()
122 b'a\0' + HASH_1 + want + b'\n' + A_SHORT_MANIFEST, m.text()
125 )
123 )
126
124
127 def testCopy(self):
125 def testCopy(self):
128 m = self.parsemanifest(20, A_SHORT_MANIFEST)
126 m = self.parsemanifest(20, A_SHORT_MANIFEST)
129 m[b'a'] = BIN_HASH_1
127 m[b'a'] = BIN_HASH_1
130 m2 = m.copy()
128 m2 = m.copy()
131 del m
129 del m
132 del m2 # make sure we don't double free() anything
130 del m2 # make sure we don't double free() anything
133
131
134 def testCompaction(self):
132 def testCompaction(self):
135 unhex = binascii.unhexlify
133 unhex = binascii.unhexlify
136 h1, h2 = unhex(HASH_1), unhex(HASH_2)
134 h1, h2 = unhex(HASH_1), unhex(HASH_2)
137 m = self.parsemanifest(20, A_SHORT_MANIFEST)
135 m = self.parsemanifest(20, A_SHORT_MANIFEST)
138 m[b'alpha'] = h1
136 m[b'alpha'] = h1
139 m[b'beta'] = h2
137 m[b'beta'] = h2
140 del m[b'foo']
138 del m[b'foo']
141 want = b'alpha\0%s\nbar/baz/qux.py\0%sl\nbeta\0%s\n' % (
139 want = b'alpha\0%s\nbar/baz/qux.py\0%sl\nbeta\0%s\n' % (
142 HASH_1,
140 HASH_1,
143 HASH_2,
141 HASH_2,
144 HASH_2,
142 HASH_2,
145 )
143 )
146 self.assertEqual(want, m.text())
144 self.assertEqual(want, m.text())
147 self.assertEqual(3, len(m))
145 self.assertEqual(3, len(m))
148 self.assertEqual([b'alpha', b'bar/baz/qux.py', b'beta'], list(m))
146 self.assertEqual([b'alpha', b'bar/baz/qux.py', b'beta'], list(m))
149 self.assertEqual(h1, m[b'alpha'])
147 self.assertEqual(h1, m[b'alpha'])
150 self.assertEqual(h2, m[b'bar/baz/qux.py'])
148 self.assertEqual(h2, m[b'bar/baz/qux.py'])
151 self.assertEqual(h2, m[b'beta'])
149 self.assertEqual(h2, m[b'beta'])
152 self.assertEqual(b'', m.flags(b'alpha'))
150 self.assertEqual(b'', m.flags(b'alpha'))
153 self.assertEqual(b'l', m.flags(b'bar/baz/qux.py'))
151 self.assertEqual(b'l', m.flags(b'bar/baz/qux.py'))
154 self.assertEqual(b'', m.flags(b'beta'))
152 self.assertEqual(b'', m.flags(b'beta'))
155 with self.assertRaises(KeyError):
153 with self.assertRaises(KeyError):
156 m[b'foo']
154 m[b'foo']
157
155
158 def testMatchException(self):
156 def testMatchException(self):
159 m = self.parsemanifest(20, A_SHORT_MANIFEST)
157 m = self.parsemanifest(20, A_SHORT_MANIFEST)
160 match = matchmod.match(util.localpath(b'/repo'), b'', [b're:.*'])
158 match = matchmod.match(util.localpath(b'/repo'), b'', [b're:.*'])
161
159
162 def filt(path):
160 def filt(path):
163 if path == b'foo':
161 if path == b'foo':
164 assert False
162 assert False
165 return True
163 return True
166
164
167 match.matchfn = filt
165 match.matchfn = filt
168 with self.assertRaises(AssertionError):
166 with self.assertRaises(AssertionError):
169 m._matches(match)
167 m._matches(match)
170
168
171 def testRemoveItem(self):
169 def testRemoveItem(self):
172 m = self.parsemanifest(20, A_SHORT_MANIFEST)
170 m = self.parsemanifest(20, A_SHORT_MANIFEST)
173 del m[b'foo']
171 del m[b'foo']
174 with self.assertRaises(KeyError):
172 with self.assertRaises(KeyError):
175 m[b'foo']
173 m[b'foo']
176 self.assertEqual(1, len(m))
174 self.assertEqual(1, len(m))
177 self.assertEqual(1, len(list(m)))
175 self.assertEqual(1, len(list(m)))
178 # now restore and make sure everything works right
176 # now restore and make sure everything works right
179 m[b'foo'] = b'a' * 20
177 m[b'foo'] = b'a' * 20
180 self.assertEqual(2, len(m))
178 self.assertEqual(2, len(m))
181 self.assertEqual(2, len(list(m)))
179 self.assertEqual(2, len(list(m)))
182
180
183 def testManifestDiff(self):
181 def testManifestDiff(self):
184 MISSING = (None, b'')
182 MISSING = (None, b'')
185 addl = b'z-only-in-left\0' + HASH_1 + b'\n'
183 addl = b'z-only-in-left\0' + HASH_1 + b'\n'
186 addr = b'z-only-in-right\0' + HASH_2 + b'x\n'
184 addr = b'z-only-in-right\0' + HASH_2 + b'x\n'
187 left = self.parsemanifest(
185 left = self.parsemanifest(
188 20, A_SHORT_MANIFEST.replace(HASH_1, HASH_3 + b'x') + addl
186 20, A_SHORT_MANIFEST.replace(HASH_1, HASH_3 + b'x') + addl
189 )
187 )
190 right = self.parsemanifest(20, A_SHORT_MANIFEST + addr)
188 right = self.parsemanifest(20, A_SHORT_MANIFEST + addr)
191 want = {
189 want = {
192 b'foo': ((BIN_HASH_3, b'x'), (BIN_HASH_1, b'')),
190 b'foo': ((BIN_HASH_3, b'x'), (BIN_HASH_1, b'')),
193 b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
191 b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
194 b'z-only-in-right': (MISSING, (BIN_HASH_2, b'x')),
192 b'z-only-in-right': (MISSING, (BIN_HASH_2, b'x')),
195 }
193 }
196 self.assertEqual(want, left.diff(right))
194 self.assertEqual(want, left.diff(right))
197
195
198 want = {
196 want = {
199 b'bar/baz/qux.py': (MISSING, (BIN_HASH_2, b'l')),
197 b'bar/baz/qux.py': (MISSING, (BIN_HASH_2, b'l')),
200 b'foo': (MISSING, (BIN_HASH_3, b'x')),
198 b'foo': (MISSING, (BIN_HASH_3, b'x')),
201 b'z-only-in-left': (MISSING, (BIN_HASH_1, b'')),
199 b'z-only-in-left': (MISSING, (BIN_HASH_1, b'')),
202 }
200 }
203 self.assertEqual(
201 self.assertEqual(
204 want, self.parsemanifest(20, EMTPY_MANIFEST).diff(left)
202 want, self.parsemanifest(20, EMTPY_MANIFEST).diff(left)
205 )
203 )
206
204
207 want = {
205 want = {
208 b'bar/baz/qux.py': ((BIN_HASH_2, b'l'), MISSING),
206 b'bar/baz/qux.py': ((BIN_HASH_2, b'l'), MISSING),
209 b'foo': ((BIN_HASH_3, b'x'), MISSING),
207 b'foo': ((BIN_HASH_3, b'x'), MISSING),
210 b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
208 b'z-only-in-left': ((BIN_HASH_1, b''), MISSING),
211 }
209 }
212 self.assertEqual(
210 self.assertEqual(
213 want, left.diff(self.parsemanifest(20, EMTPY_MANIFEST))
211 want, left.diff(self.parsemanifest(20, EMTPY_MANIFEST))
214 )
212 )
215 copy = right.copy()
213 copy = right.copy()
216 del copy[b'z-only-in-right']
214 del copy[b'z-only-in-right']
217 del right[b'foo']
215 del right[b'foo']
218 want = {
216 want = {
219 b'foo': (MISSING, (BIN_HASH_1, b'')),
217 b'foo': (MISSING, (BIN_HASH_1, b'')),
220 b'z-only-in-right': ((BIN_HASH_2, b'x'), MISSING),
218 b'z-only-in-right': ((BIN_HASH_2, b'x'), MISSING),
221 }
219 }
222 self.assertEqual(want, right.diff(copy))
220 self.assertEqual(want, right.diff(copy))
223
221
224 short = self.parsemanifest(20, A_SHORT_MANIFEST)
222 short = self.parsemanifest(20, A_SHORT_MANIFEST)
225 pruned = short.copy()
223 pruned = short.copy()
226 del pruned[b'foo']
224 del pruned[b'foo']
227 want = {
225 want = {
228 b'foo': ((BIN_HASH_1, b''), MISSING),
226 b'foo': ((BIN_HASH_1, b''), MISSING),
229 }
227 }
230 self.assertEqual(want, short.diff(pruned))
228 self.assertEqual(want, short.diff(pruned))
231 want = {
229 want = {
232 b'foo': (MISSING, (BIN_HASH_1, b'')),
230 b'foo': (MISSING, (BIN_HASH_1, b'')),
233 }
231 }
234 self.assertEqual(want, pruned.diff(short))
232 self.assertEqual(want, pruned.diff(short))
235 want = {
233 want = {
236 b'bar/baz/qux.py': None,
234 b'bar/baz/qux.py': None,
237 b'foo': (MISSING, (BIN_HASH_1, b'')),
235 b'foo': (MISSING, (BIN_HASH_1, b'')),
238 }
236 }
239 self.assertEqual(want, pruned.diff(short, clean=True))
237 self.assertEqual(want, pruned.diff(short, clean=True))
240
238
241 def testReversedLines(self):
239 def testReversedLines(self):
242 backwards = b''.join(
240 backwards = b''.join(
243 l + b'\n' for l in reversed(A_SHORT_MANIFEST.split(b'\n')) if l
241 l + b'\n' for l in reversed(A_SHORT_MANIFEST.split(b'\n')) if l
244 )
242 )
245 try:
243 try:
246 self.parsemanifest(20, backwards)
244 self.parsemanifest(20, backwards)
247 self.fail('Should have raised ValueError')
245 self.fail('Should have raised ValueError')
248 except ValueError as v:
246 except ValueError as v:
249 self.assertIn('Manifest lines not in sorted order.', str(v))
247 self.assertIn('Manifest lines not in sorted order.', str(v))
250
248
251 def testNoTerminalNewline(self):
249 def testNoTerminalNewline(self):
252 try:
250 try:
253 self.parsemanifest(20, A_SHORT_MANIFEST + b'wat')
251 self.parsemanifest(20, A_SHORT_MANIFEST + b'wat')
254 self.fail('Should have raised ValueError')
252 self.fail('Should have raised ValueError')
255 except ValueError as v:
253 except ValueError as v:
256 self.assertIn('Manifest did not end in a newline.', str(v))
254 self.assertIn('Manifest did not end in a newline.', str(v))
257
255
258 def testNoNewLineAtAll(self):
256 def testNoNewLineAtAll(self):
259 try:
257 try:
260 self.parsemanifest(20, b'wat')
258 self.parsemanifest(20, b'wat')
261 self.fail('Should have raised ValueError')
259 self.fail('Should have raised ValueError')
262 except ValueError as v:
260 except ValueError as v:
263 self.assertIn('Manifest did not end in a newline.', str(v))
261 self.assertIn('Manifest did not end in a newline.', str(v))
264
262
265 def testHugeManifest(self):
263 def testHugeManifest(self):
266 m = self.parsemanifest(20, A_HUGE_MANIFEST)
264 m = self.parsemanifest(20, A_HUGE_MANIFEST)
267 self.assertEqual(HUGE_MANIFEST_ENTRIES, len(m))
265 self.assertEqual(HUGE_MANIFEST_ENTRIES, len(m))
268 self.assertEqual(len(m), len(list(m)))
266 self.assertEqual(len(m), len(list(m)))
269
267
270 def testMatchesMetadata(self):
268 def testMatchesMetadata(self):
271 """Tests matches() for a few specific files to make sure that both
269 """Tests matches() for a few specific files to make sure that both
272 the set of files as well as their flags and nodeids are correct in
270 the set of files as well as their flags and nodeids are correct in
273 the resulting manifest."""
271 the resulting manifest."""
274 m = self.parsemanifest(20, A_HUGE_MANIFEST)
272 m = self.parsemanifest(20, A_HUGE_MANIFEST)
275
273
276 match = matchmod.exact([b'file1', b'file200', b'file300'])
274 match = matchmod.exact([b'file1', b'file200', b'file300'])
277 m2 = m._matches(match)
275 m2 = m._matches(match)
278
276
279 w = (b'file1\0%sx\n' b'file200\0%sl\n' b'file300\0%s\n') % (
277 w = (b'file1\0%sx\n' b'file200\0%sl\n' b'file300\0%s\n') % (
280 HASH_2,
278 HASH_2,
281 HASH_1,
279 HASH_1,
282 HASH_1,
280 HASH_1,
283 )
281 )
284 self.assertEqual(w, m2.text())
282 self.assertEqual(w, m2.text())
285
283
286 def testMatchesNonexistentFile(self):
284 def testMatchesNonexistentFile(self):
287 """Tests matches() for a small set of specific files, including one
285 """Tests matches() for a small set of specific files, including one
288 nonexistent file to make sure in only matches against existing files.
286 nonexistent file to make sure in only matches against existing files.
289 """
287 """
290 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
288 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
291
289
292 match = matchmod.exact(
290 match = matchmod.exact(
293 [b'a/b/c/bar.txt', b'a/b/d/qux.py', b'readme.txt', b'nonexistent']
291 [b'a/b/c/bar.txt', b'a/b/d/qux.py', b'readme.txt', b'nonexistent']
294 )
292 )
295 m2 = m._matches(match)
293 m2 = m._matches(match)
296
294
297 self.assertEqual(
295 self.assertEqual(
298 [b'a/b/c/bar.txt', b'a/b/d/qux.py', b'readme.txt'], m2.keys()
296 [b'a/b/c/bar.txt', b'a/b/d/qux.py', b'readme.txt'], m2.keys()
299 )
297 )
300
298
301 def testMatchesNonexistentDirectory(self):
299 def testMatchesNonexistentDirectory(self):
302 """Tests matches() for a relpath match on a directory that doesn't
300 """Tests matches() for a relpath match on a directory that doesn't
303 actually exist."""
301 actually exist."""
304 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
302 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
305
303
306 match = matchmod.match(
304 match = matchmod.match(
307 util.localpath(b'/repo'), b'', [b'a/f'], default=b'relpath'
305 util.localpath(b'/repo'), b'', [b'a/f'], default=b'relpath'
308 )
306 )
309 m2 = m._matches(match)
307 m2 = m._matches(match)
310
308
311 self.assertEqual([], m2.keys())
309 self.assertEqual([], m2.keys())
312
310
313 def testMatchesExactLarge(self):
311 def testMatchesExactLarge(self):
314 """Tests matches() for files matching a large list of exact files."""
312 """Tests matches() for files matching a large list of exact files."""
315 m = self.parsemanifest(20, A_HUGE_MANIFEST)
313 m = self.parsemanifest(20, A_HUGE_MANIFEST)
316
314
317 flist = m.keys()[80:300]
315 flist = m.keys()[80:300]
318 match = matchmod.exact(flist)
316 match = matchmod.exact(flist)
319 m2 = m._matches(match)
317 m2 = m._matches(match)
320
318
321 self.assertEqual(flist, m2.keys())
319 self.assertEqual(flist, m2.keys())
322
320
323 def testMatchesFull(self):
321 def testMatchesFull(self):
324 '''Tests matches() for what should be a full match.'''
322 '''Tests matches() for what should be a full match.'''
325 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
323 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
326
324
327 match = matchmod.match(util.localpath(b'/repo'), b'', [b''])
325 match = matchmod.match(util.localpath(b'/repo'), b'', [b''])
328 m2 = m._matches(match)
326 m2 = m._matches(match)
329
327
330 self.assertEqual(m.keys(), m2.keys())
328 self.assertEqual(m.keys(), m2.keys())
331
329
332 def testMatchesDirectory(self):
330 def testMatchesDirectory(self):
333 """Tests matches() on a relpath match on a directory, which should
331 """Tests matches() on a relpath match on a directory, which should
334 match against all files within said directory."""
332 match against all files within said directory."""
335 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
333 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
336
334
337 match = matchmod.match(
335 match = matchmod.match(
338 util.localpath(b'/repo'), b'', [b'a/b'], default=b'relpath'
336 util.localpath(b'/repo'), b'', [b'a/b'], default=b'relpath'
339 )
337 )
340 m2 = m._matches(match)
338 m2 = m._matches(match)
341
339
342 self.assertEqual(
340 self.assertEqual(
343 [
341 [
344 b'a/b/c/bar.py',
342 b'a/b/c/bar.py',
345 b'a/b/c/bar.txt',
343 b'a/b/c/bar.txt',
346 b'a/b/c/foo.py',
344 b'a/b/c/foo.py',
347 b'a/b/c/foo.txt',
345 b'a/b/c/foo.txt',
348 b'a/b/d/baz.py',
346 b'a/b/d/baz.py',
349 b'a/b/d/qux.py',
347 b'a/b/d/qux.py',
350 b'a/b/d/ten.txt',
348 b'a/b/d/ten.txt',
351 b'a/b/dog.py',
349 b'a/b/dog.py',
352 b'a/b/fish.py',
350 b'a/b/fish.py',
353 ],
351 ],
354 m2.keys(),
352 m2.keys(),
355 )
353 )
356
354
357 def testMatchesExactPath(self):
355 def testMatchesExactPath(self):
358 """Tests matches() on an exact match on a directory, which should
356 """Tests matches() on an exact match on a directory, which should
359 result in an empty manifest because you can't perform an exact match
357 result in an empty manifest because you can't perform an exact match
360 against a directory."""
358 against a directory."""
361 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
359 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
362
360
363 match = matchmod.exact([b'a/b'])
361 match = matchmod.exact([b'a/b'])
364 m2 = m._matches(match)
362 m2 = m._matches(match)
365
363
366 self.assertEqual([], m2.keys())
364 self.assertEqual([], m2.keys())
367
365
368 def testMatchesCwd(self):
366 def testMatchesCwd(self):
369 """Tests matches() on a relpath match with the current directory ('.')
367 """Tests matches() on a relpath match with the current directory ('.')
370 when not in the root directory."""
368 when not in the root directory."""
371 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
369 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
372
370
373 match = matchmod.match(
371 match = matchmod.match(
374 util.localpath(b'/repo'), b'a/b', [b'.'], default=b'relpath'
372 util.localpath(b'/repo'), b'a/b', [b'.'], default=b'relpath'
375 )
373 )
376 m2 = m._matches(match)
374 m2 = m._matches(match)
377
375
378 self.assertEqual(
376 self.assertEqual(
379 [
377 [
380 b'a/b/c/bar.py',
378 b'a/b/c/bar.py',
381 b'a/b/c/bar.txt',
379 b'a/b/c/bar.txt',
382 b'a/b/c/foo.py',
380 b'a/b/c/foo.py',
383 b'a/b/c/foo.txt',
381 b'a/b/c/foo.txt',
384 b'a/b/d/baz.py',
382 b'a/b/d/baz.py',
385 b'a/b/d/qux.py',
383 b'a/b/d/qux.py',
386 b'a/b/d/ten.txt',
384 b'a/b/d/ten.txt',
387 b'a/b/dog.py',
385 b'a/b/dog.py',
388 b'a/b/fish.py',
386 b'a/b/fish.py',
389 ],
387 ],
390 m2.keys(),
388 m2.keys(),
391 )
389 )
392
390
393 def testMatchesWithPattern(self):
391 def testMatchesWithPattern(self):
394 """Tests matches() for files matching a pattern that reside
392 """Tests matches() for files matching a pattern that reside
395 deeper than the specified directory."""
393 deeper than the specified directory."""
396 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
394 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
397
395
398 match = matchmod.match(util.localpath(b'/repo'), b'', [b'a/b/*/*.txt'])
396 match = matchmod.match(util.localpath(b'/repo'), b'', [b'a/b/*/*.txt'])
399 m2 = m._matches(match)
397 m2 = m._matches(match)
400
398
401 self.assertEqual(
399 self.assertEqual(
402 [b'a/b/c/bar.txt', b'a/b/c/foo.txt', b'a/b/d/ten.txt'], m2.keys()
400 [b'a/b/c/bar.txt', b'a/b/c/foo.txt', b'a/b/d/ten.txt'], m2.keys()
403 )
401 )
404
402
405
403
406 class testmanifestdict(unittest.TestCase, basemanifesttests):
404 class testmanifestdict(unittest.TestCase, basemanifesttests):
407 def parsemanifest(self, nodelen, text):
405 def parsemanifest(self, nodelen, text):
408 return manifestmod.manifestdict(nodelen, text)
406 return manifestmod.manifestdict(nodelen, text)
409
407
410 def testManifestLongHashes(self):
408 def testManifestLongHashes(self):
411 m = self.parsemanifest(32, b'a\0' + b'f' * 64 + b'\n')
409 m = self.parsemanifest(32, b'a\0' + b'f' * 64 + b'\n')
412 self.assertEqual(binascii.unhexlify(b'f' * 64), m[b'a'])
410 self.assertEqual(binascii.unhexlify(b'f' * 64), m[b'a'])
413
411
414 def testObviouslyBogusManifest(self):
412 def testObviouslyBogusManifest(self):
415 # This is a 163k manifest that came from oss-fuzz. It was a
413 # This is a 163k manifest that came from oss-fuzz. It was a
416 # timeout there, but when run normally it doesn't seem to
414 # timeout there, but when run normally it doesn't seem to
417 # present any particular slowness.
415 # present any particular slowness.
418 data = zlib.decompress(
416 data = zlib.decompress(
419 b'x\x9c\xed\xce;\n\x83\x00\x10\x04\xd0\x8deNa\x93~\xf1\x03\xc9q\xf4'
417 b'x\x9c\xed\xce;\n\x83\x00\x10\x04\xd0\x8deNa\x93~\xf1\x03\xc9q\xf4'
420 b'\x14\xeaU\xbdB\xda\xd4\xe6Cj\xc1FA\xde+\x86\xe9f\xa2\xfci\xbb\xfb'
418 b'\x14\xeaU\xbdB\xda\xd4\xe6Cj\xc1FA\xde+\x86\xe9f\xa2\xfci\xbb\xfb'
421 b'\xa3\xef\xea\xba\xca\x7fk\x86q\x9a\xc6\xc8\xcc&\xb3\xcf\xf8\xb8|#'
419 b'\xa3\xef\xea\xba\xca\x7fk\x86q\x9a\xc6\xc8\xcc&\xb3\xcf\xf8\xb8|#'
422 b'\x8a9\x00\xd8\xe6v\xf4\x01N\xe1\n\x00\x00\x00\x00\x00\x00\x00\x00'
420 b'\x8a9\x00\xd8\xe6v\xf4\x01N\xe1\n\x00\x00\x00\x00\x00\x00\x00\x00'
423 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
421 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
424 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
422 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
425 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
423 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
426 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
424 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
427 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
425 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
428 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
426 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
429 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
427 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
430 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
428 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
431 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
429 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
432 b'\x00\x00\xc0\x8aey\x1d}\x01\xd8\xe0\xb9\xf3\xde\x1b\xcf\x17'
430 b'\x00\x00\xc0\x8aey\x1d}\x01\xd8\xe0\xb9\xf3\xde\x1b\xcf\x17'
433 b'\xac\xbe'
431 b'\xac\xbe'
434 )
432 )
435 with self.assertRaises(ValueError):
433 with self.assertRaises(ValueError):
436 self.parsemanifest(20, data)
434 self.parsemanifest(20, data)
437
435
438
436
439 class testtreemanifest(unittest.TestCase, basemanifesttests):
437 class testtreemanifest(unittest.TestCase, basemanifesttests):
440 def parsemanifest(self, nodelen, text):
438 def parsemanifest(self, nodelen, text):
441 return manifestmod.treemanifest(sha1nodeconstants, b'', text)
439 return manifestmod.treemanifest(sha1nodeconstants, b'', text)
442
440
443 def testWalkSubtrees(self):
441 def testWalkSubtrees(self):
444 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
442 m = self.parsemanifest(20, A_DEEPER_MANIFEST)
445
443
446 dirs = [s._dir for s in m.walksubtrees()]
444 dirs = [s._dir for s in m.walksubtrees()]
447 self.assertEqual(
445 self.assertEqual(
448 sorted(
446 sorted(
449 [b'', b'a/', b'a/c/', b'a/d/', b'a/b/', b'a/b/c/', b'a/b/d/']
447 [b'', b'a/', b'a/c/', b'a/d/', b'a/b/', b'a/b/c/', b'a/b/d/']
450 ),
448 ),
451 sorted(dirs),
449 sorted(dirs),
452 )
450 )
453
451
454 match = matchmod.match(util.localpath(b'/repo'), b'', [b'path:a/b/'])
452 match = matchmod.match(util.localpath(b'/repo'), b'', [b'path:a/b/'])
455 dirs = [s._dir for s in m.walksubtrees(matcher=match)]
453 dirs = [s._dir for s in m.walksubtrees(matcher=match)]
456 self.assertEqual(sorted([b'a/b/', b'a/b/c/', b'a/b/d/']), sorted(dirs))
454 self.assertEqual(sorted([b'a/b/', b'a/b/c/', b'a/b/d/']), sorted(dirs))
457
455
458
456
459 if __name__ == '__main__':
457 if __name__ == '__main__':
460 silenttestrunner.main(__name__)
458 silenttestrunner.main(__name__)
General Comments 0
You need to be logged in to leave comments. Login now