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