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