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