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