##// END OF EJS Templates
test-manifest.py: separate out test for double-free after copy()...
Martin von Zweigbergk -
r24465:bb8e2b1a default
parent child Browse files
Show More
@@ -1,232 +1,236 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
8
9 HASH_1 = '1' * 40
9 HASH_1 = '1' * 40
10 HASH_2 = 'f' * 40
10 HASH_2 = 'f' * 40
11 HASH_3 = '1234567890abcdef0987654321deadbeef0fcafe'
11 HASH_3 = '1234567890abcdef0987654321deadbeef0fcafe'
12 A_SHORT_MANIFEST = (
12 A_SHORT_MANIFEST = (
13 'bar/baz/qux.py\0%(hash2)s%(flag2)s\n'
13 'bar/baz/qux.py\0%(hash2)s%(flag2)s\n'
14 'foo\0%(hash1)s%(flag1)s\n'
14 'foo\0%(hash1)s%(flag1)s\n'
15 ) % {'hash1': HASH_1,
15 ) % {'hash1': HASH_1,
16 'flag1': '',
16 'flag1': '',
17 'hash2': HASH_2,
17 'hash2': HASH_2,
18 'flag2': 'l',
18 'flag2': 'l',
19 }
19 }
20
20
21 HUGE_MANIFEST_ENTRIES = 200001
21 HUGE_MANIFEST_ENTRIES = 200001
22
22
23 A_HUGE_MANIFEST = ''.join(sorted(
23 A_HUGE_MANIFEST = ''.join(sorted(
24 'file%d\0%s%s\n' % (i, h, f) for i, h, f in
24 'file%d\0%s%s\n' % (i, h, f) for i, h, f in
25 itertools.izip(xrange(200001),
25 itertools.izip(xrange(200001),
26 itertools.cycle((HASH_1, HASH_2)),
26 itertools.cycle((HASH_1, HASH_2)),
27 itertools.cycle(('', 'x', 'l')))))
27 itertools.cycle(('', 'x', 'l')))))
28
28
29 class testmanifest(unittest.TestCase):
29 class testmanifest(unittest.TestCase):
30
30
31 def assertIn(self, thing, container, msg=None):
31 def assertIn(self, thing, container, msg=None):
32 # assertIn new in 2.7, use it if available, otherwise polyfill
32 # assertIn new in 2.7, use it if available, otherwise polyfill
33 sup = getattr(unittest.TestCase, 'assertIn', False)
33 sup = getattr(unittest.TestCase, 'assertIn', False)
34 if sup:
34 if sup:
35 return sup(self, thing, container, msg=msg)
35 return sup(self, thing, container, msg=msg)
36 if not msg:
36 if not msg:
37 msg = 'Expected %r in %r' % (thing, container)
37 msg = 'Expected %r in %r' % (thing, container)
38 self.assert_(thing in container, msg)
38 self.assert_(thing in container, msg)
39
39
40 def testEmptyManifest(self):
40 def testEmptyManifest(self):
41 m = manifestmod._lazymanifest('')
41 m = manifestmod._lazymanifest('')
42 self.assertEqual(0, len(m))
42 self.assertEqual(0, len(m))
43 self.assertEqual([], list(m.iterentries()))
43 self.assertEqual([], list(m.iterentries()))
44
44
45 def testManifest(self):
45 def testManifest(self):
46 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
46 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
47 want = [
47 want = [
48 ('bar/baz/qux.py', binascii.unhexlify(HASH_2), 'l'),
48 ('bar/baz/qux.py', binascii.unhexlify(HASH_2), 'l'),
49 ('foo', binascii.unhexlify(HASH_1), ''),
49 ('foo', binascii.unhexlify(HASH_1), ''),
50 ]
50 ]
51 self.assertEqual(len(want), len(m))
51 self.assertEqual(len(want), len(m))
52 self.assertEqual(want, list(m.iterentries()))
52 self.assertEqual(want, list(m.iterentries()))
53 self.assertEqual((binascii.unhexlify(HASH_1), ''), m['foo'])
53 self.assertEqual((binascii.unhexlify(HASH_1), ''), m['foo'])
54 self.assertRaises(KeyError, lambda : m['wat'])
54 self.assertRaises(KeyError, lambda : m['wat'])
55 self.assertEqual((binascii.unhexlify(HASH_2), 'l'),
55 self.assertEqual((binascii.unhexlify(HASH_2), 'l'),
56 m['bar/baz/qux.py'])
56 m['bar/baz/qux.py'])
57
57
58 def testSetItem(self):
58 def testSetItem(self):
59 want = binascii.unhexlify(HASH_1), ''
59 want = binascii.unhexlify(HASH_1), ''
60
60
61 m = manifestmod._lazymanifest('')
61 m = manifestmod._lazymanifest('')
62 m['a'] = want
62 m['a'] = want
63 self.assertIn('a', m)
63 self.assertIn('a', m)
64 self.assertEqual(want, m['a'])
64 self.assertEqual(want, m['a'])
65 self.assertEqual('a\0' + HASH_1 + '\n', m.text())
65 self.assertEqual('a\0' + HASH_1 + '\n', m.text())
66
66
67 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
67 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
68 m['a'] = want
68 m['a'] = want
69 self.assertEqual(want, m['a'])
69 self.assertEqual(want, m['a'])
70 self.assertEqual('a\0' + HASH_1 + '\n' + A_SHORT_MANIFEST,
70 self.assertEqual('a\0' + HASH_1 + '\n' + A_SHORT_MANIFEST,
71 m.text())
71 m.text())
72
73 def testCopy(self):
74 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
75 m['a'] = binascii.unhexlify(HASH_1), ''
72 m2 = m.copy()
76 m2 = m.copy()
73 del m
77 del m
74 del m2 # make sure we don't double free() anything
78 del m2 # make sure we don't double free() anything
75
79
76 def testCompaction(self):
80 def testCompaction(self):
77 unhex = binascii.unhexlify
81 unhex = binascii.unhexlify
78 h1, h2 = unhex(HASH_1), unhex(HASH_2)
82 h1, h2 = unhex(HASH_1), unhex(HASH_2)
79 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
83 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
80 m['alpha'] = h1, ''
84 m['alpha'] = h1, ''
81 m['beta'] = h2, ''
85 m['beta'] = h2, ''
82 del m['foo']
86 del m['foo']
83 want = 'alpha\0%s\nbar/baz/qux.py\0%sl\nbeta\0%s\n' % (
87 want = 'alpha\0%s\nbar/baz/qux.py\0%sl\nbeta\0%s\n' % (
84 HASH_1, HASH_2, HASH_2)
88 HASH_1, HASH_2, HASH_2)
85 self.assertEqual(want, m.text())
89 self.assertEqual(want, m.text())
86 self.assertEqual(3, len(m))
90 self.assertEqual(3, len(m))
87 self.assertEqual((h1, ''), m['alpha'])
91 self.assertEqual((h1, ''), m['alpha'])
88 self.assertEqual((h2, ''), m['beta'])
92 self.assertEqual((h2, ''), m['beta'])
89 self.assertRaises(KeyError, lambda : m['foo'])
93 self.assertRaises(KeyError, lambda : m['foo'])
90 w = [('alpha', h1, ''), ('bar/baz/qux.py', h2, 'l'), ('beta', h2, '')]
94 w = [('alpha', h1, ''), ('bar/baz/qux.py', h2, 'l'), ('beta', h2, '')]
91 self.assertEqual(w, list(m.iterentries()))
95 self.assertEqual(w, list(m.iterentries()))
92
96
93 def testSetGetNodeSuffix(self):
97 def testSetGetNodeSuffix(self):
94 clean = manifestmod._lazymanifest(A_SHORT_MANIFEST)
98 clean = manifestmod._lazymanifest(A_SHORT_MANIFEST)
95 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
99 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
96 h, f = m['foo']
100 h, f = m['foo']
97 want = h + 'a', f
101 want = h + 'a', f
98 # Merge code wants to set 21-byte fake hashes at times
102 # Merge code wants to set 21-byte fake hashes at times
99 m['foo'] = want
103 m['foo'] = want
100 self.assertEqual(want, m['foo'])
104 self.assertEqual(want, m['foo'])
101 self.assertEqual([('bar/baz/qux.py', binascii.unhexlify(HASH_2), 'l'),
105 self.assertEqual([('bar/baz/qux.py', binascii.unhexlify(HASH_2), 'l'),
102 ('foo', binascii.unhexlify(HASH_1) + 'a', '')],
106 ('foo', binascii.unhexlify(HASH_1) + 'a', '')],
103 list(m.iterentries()))
107 list(m.iterentries()))
104 # Sometimes it even tries a 22-byte fake hash, but we can
108 # Sometimes it even tries a 22-byte fake hash, but we can
105 # return 21 and it'll work out
109 # return 21 and it'll work out
106 m['foo'] = want[0] + '+', f
110 m['foo'] = want[0] + '+', f
107 self.assertEqual(want, m['foo'])
111 self.assertEqual(want, m['foo'])
108 # make sure the suffix survives a copy
112 # make sure the suffix survives a copy
109 m2 = m.filtercopy(lambda x: x == 'foo')
113 m2 = m.filtercopy(lambda x: x == 'foo')
110 self.assertEqual(want, m2['foo'])
114 self.assertEqual(want, m2['foo'])
111 self.assertEqual(1, len(m2))
115 self.assertEqual(1, len(m2))
112 self.assertEqual(('foo\0%s\n' % HASH_1), m2.text())
116 self.assertEqual(('foo\0%s\n' % HASH_1), m2.text())
113 m2 = m.copy()
117 m2 = m.copy()
114 self.assertEqual(want, m2['foo'])
118 self.assertEqual(want, m2['foo'])
115 # suffix with iteration
119 # suffix with iteration
116 self.assertEqual([('bar/baz/qux.py', binascii.unhexlify(HASH_2), 'l'),
120 self.assertEqual([('bar/baz/qux.py', binascii.unhexlify(HASH_2), 'l'),
117 ('foo', want[0], '')], list(m.iterentries()))
121 ('foo', want[0], '')], list(m.iterentries()))
118 # shows up in diff
122 # shows up in diff
119 self.assertEqual({'foo': (want, (h, ''))}, m.diff(clean))
123 self.assertEqual({'foo': (want, (h, ''))}, m.diff(clean))
120 self.assertEqual({'foo': ((h, ''), want)}, clean.diff(m))
124 self.assertEqual({'foo': ((h, ''), want)}, clean.diff(m))
121
125
122 def testFilterCopyException(self):
126 def testFilterCopyException(self):
123 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
127 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
124 def filt(path):
128 def filt(path):
125 if path == 'foo':
129 if path == 'foo':
126 assert False
130 assert False
127 return True
131 return True
128 self.assertRaises(AssertionError, m.filtercopy, filt)
132 self.assertRaises(AssertionError, m.filtercopy, filt)
129
133
130 def testRemoveItem(self):
134 def testRemoveItem(self):
131 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
135 m = manifestmod._lazymanifest(A_SHORT_MANIFEST)
132 del m['foo']
136 del m['foo']
133 self.assertRaises(KeyError, lambda : m['foo'])
137 self.assertRaises(KeyError, lambda : m['foo'])
134 self.assertEqual(1, len(m))
138 self.assertEqual(1, len(m))
135 self.assertEqual(1, len(list(m)))
139 self.assertEqual(1, len(list(m)))
136 # now restore and make sure everything works right
140 # now restore and make sure everything works right
137 m['foo'] = 'a' * 20, ''
141 m['foo'] = 'a' * 20, ''
138 self.assertEqual(2, len(m))
142 self.assertEqual(2, len(m))
139 self.assertEqual(2, len(list(m)))
143 self.assertEqual(2, len(list(m)))
140
144
141 def testManifestDiff(self):
145 def testManifestDiff(self):
142 MISSING = (None, '')
146 MISSING = (None, '')
143 addl = 'z-only-in-left\0' + HASH_1 + '\n'
147 addl = 'z-only-in-left\0' + HASH_1 + '\n'
144 addr = 'z-only-in-right\0' + HASH_2 + 'x\n'
148 addr = 'z-only-in-right\0' + HASH_2 + 'x\n'
145 left = manifestmod._lazymanifest(
149 left = manifestmod._lazymanifest(
146 A_SHORT_MANIFEST.replace(HASH_1, HASH_3 + 'x') + addl)
150 A_SHORT_MANIFEST.replace(HASH_1, HASH_3 + 'x') + addl)
147 right = manifestmod._lazymanifest(A_SHORT_MANIFEST + addr)
151 right = manifestmod._lazymanifest(A_SHORT_MANIFEST + addr)
148 want = {
152 want = {
149 'foo': ((binascii.unhexlify(HASH_3), 'x'),
153 'foo': ((binascii.unhexlify(HASH_3), 'x'),
150 (binascii.unhexlify(HASH_1), '')),
154 (binascii.unhexlify(HASH_1), '')),
151 'z-only-in-left': ((binascii.unhexlify(HASH_1), ''), MISSING),
155 'z-only-in-left': ((binascii.unhexlify(HASH_1), ''), MISSING),
152 'z-only-in-right': (MISSING, (binascii.unhexlify(HASH_2), 'x')),
156 'z-only-in-right': (MISSING, (binascii.unhexlify(HASH_2), 'x')),
153 }
157 }
154 self.assertEqual(want, left.diff(right))
158 self.assertEqual(want, left.diff(right))
155
159
156 want = {
160 want = {
157 'bar/baz/qux.py': (MISSING, (binascii.unhexlify(HASH_2), 'l')),
161 'bar/baz/qux.py': (MISSING, (binascii.unhexlify(HASH_2), 'l')),
158 'foo': (MISSING, (binascii.unhexlify(HASH_3), 'x')),
162 'foo': (MISSING, (binascii.unhexlify(HASH_3), 'x')),
159 'z-only-in-left': (MISSING, (binascii.unhexlify(HASH_1), '')),
163 'z-only-in-left': (MISSING, (binascii.unhexlify(HASH_1), '')),
160 }
164 }
161 self.assertEqual(want, manifestmod._lazymanifest('').diff(left))
165 self.assertEqual(want, manifestmod._lazymanifest('').diff(left))
162
166
163 want = {
167 want = {
164 'bar/baz/qux.py': ((binascii.unhexlify(HASH_2), 'l'), MISSING),
168 'bar/baz/qux.py': ((binascii.unhexlify(HASH_2), 'l'), MISSING),
165 'foo': ((binascii.unhexlify(HASH_3), 'x'), MISSING),
169 'foo': ((binascii.unhexlify(HASH_3), 'x'), MISSING),
166 'z-only-in-left': ((binascii.unhexlify(HASH_1), ''), MISSING),
170 'z-only-in-left': ((binascii.unhexlify(HASH_1), ''), MISSING),
167 }
171 }
168 self.assertEqual(want, left.diff(manifestmod._lazymanifest('')))
172 self.assertEqual(want, left.diff(manifestmod._lazymanifest('')))
169 copy = right.copy()
173 copy = right.copy()
170 del copy['z-only-in-right']
174 del copy['z-only-in-right']
171 del right['foo']
175 del right['foo']
172 want = {
176 want = {
173 'foo': (MISSING, (binascii.unhexlify(HASH_1), '')),
177 'foo': (MISSING, (binascii.unhexlify(HASH_1), '')),
174 'z-only-in-right': ((binascii.unhexlify(HASH_2), 'x'), MISSING),
178 'z-only-in-right': ((binascii.unhexlify(HASH_2), 'x'), MISSING),
175 }
179 }
176 self.assertEqual(want, right.diff(copy))
180 self.assertEqual(want, right.diff(copy))
177
181
178 short = manifestmod._lazymanifest(A_SHORT_MANIFEST)
182 short = manifestmod._lazymanifest(A_SHORT_MANIFEST)
179 pruned = short.copy()
183 pruned = short.copy()
180 del pruned['foo']
184 del pruned['foo']
181 want = {
185 want = {
182 'foo': ((binascii.unhexlify(HASH_1), ''), MISSING),
186 'foo': ((binascii.unhexlify(HASH_1), ''), MISSING),
183 }
187 }
184 self.assertEqual(want, short.diff(pruned))
188 self.assertEqual(want, short.diff(pruned))
185 want = {
189 want = {
186 'foo': (MISSING, (binascii.unhexlify(HASH_1), '')),
190 'foo': (MISSING, (binascii.unhexlify(HASH_1), '')),
187 }
191 }
188 self.assertEqual(want, pruned.diff(short))
192 self.assertEqual(want, pruned.diff(short))
189 want = {
193 want = {
190 'bar/baz/qux.py': None,
194 'bar/baz/qux.py': None,
191 'foo': (MISSING, (binascii.unhexlify(HASH_1), '')),
195 'foo': (MISSING, (binascii.unhexlify(HASH_1), '')),
192 }
196 }
193 self.assertEqual(want, pruned.diff(short, True))
197 self.assertEqual(want, pruned.diff(short, True))
194
198
195 def testReversedLines(self):
199 def testReversedLines(self):
196 backwards = ''.join(
200 backwards = ''.join(
197 l + '\n' for l in reversed(A_SHORT_MANIFEST.split('\n')) if l)
201 l + '\n' for l in reversed(A_SHORT_MANIFEST.split('\n')) if l)
198 try:
202 try:
199 manifestmod._lazymanifest(backwards)
203 manifestmod._lazymanifest(backwards)
200 self.fail('Should have raised ValueError')
204 self.fail('Should have raised ValueError')
201 except ValueError, v:
205 except ValueError, v:
202 self.assertIn('Manifest lines not in sorted order.', str(v))
206 self.assertIn('Manifest lines not in sorted order.', str(v))
203
207
204 def testNoTerminalNewline(self):
208 def testNoTerminalNewline(self):
205 try:
209 try:
206 manifestmod._lazymanifest(A_SHORT_MANIFEST + 'wat')
210 manifestmod._lazymanifest(A_SHORT_MANIFEST + 'wat')
207 self.fail('Should have raised ValueError')
211 self.fail('Should have raised ValueError')
208 except ValueError, v:
212 except ValueError, v:
209 self.assertIn('Manifest did not end in a newline.', str(v))
213 self.assertIn('Manifest did not end in a newline.', str(v))
210
214
211 def testNoNewLineAtAll(self):
215 def testNoNewLineAtAll(self):
212 try:
216 try:
213 manifestmod._lazymanifest('wat')
217 manifestmod._lazymanifest('wat')
214 self.fail('Should have raised ValueError')
218 self.fail('Should have raised ValueError')
215 except ValueError, v:
219 except ValueError, v:
216 self.assertIn('Manifest did not end in a newline.', str(v))
220 self.assertIn('Manifest did not end in a newline.', str(v))
217
221
218 def testHugeManifest(self):
222 def testHugeManifest(self):
219 m = manifestmod._lazymanifest(A_HUGE_MANIFEST)
223 m = manifestmod._lazymanifest(A_HUGE_MANIFEST)
220 self.assertEqual(HUGE_MANIFEST_ENTRIES, len(m))
224 self.assertEqual(HUGE_MANIFEST_ENTRIES, len(m))
221 self.assertEqual(len(m), len(list(m)))
225 self.assertEqual(len(m), len(list(m)))
222
226
223 def testIntersectFiles(self):
227 def testIntersectFiles(self):
224 m = manifestmod.manifestdict(A_HUGE_MANIFEST)
228 m = manifestmod.manifestdict(A_HUGE_MANIFEST)
225 m2 = m.intersectfiles(['file1', 'file200', 'file300'])
229 m2 = m.intersectfiles(['file1', 'file200', 'file300'])
226 w = ('file1\0%sx\n'
230 w = ('file1\0%sx\n'
227 'file200\0%sl\n'
231 'file200\0%sl\n'
228 'file300\0%s\n') % (HASH_2, HASH_1, HASH_1)
232 'file300\0%s\n') % (HASH_2, HASH_1, HASH_1)
229 self.assertEqual(w, m2.text())
233 self.assertEqual(w, m2.text())
230
234
231 if __name__ == '__main__':
235 if __name__ == '__main__':
232 silenttestrunner.main(__name__)
236 silenttestrunner.main(__name__)
General Comments 0
You need to be logged in to leave comments. Login now