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