Update version number and release date.
[python/dscho.git] / Lib / test / test_mmap.py
bloba6796d5279adbf898e96cdfd1a1040a64cbf9e6d
1 from test.test_support import verify, vereq, TESTFN
2 import mmap
3 import os, re
5 PAGESIZE = mmap.PAGESIZE
7 def test_both():
8 "Test mmap module on Unix systems and Windows"
10 # Create a file to be mmap'ed.
11 if os.path.exists(TESTFN):
12 os.unlink(TESTFN)
13 f = open(TESTFN, 'w+')
15 try: # unlink TESTFN no matter what
16 # Write 2 pages worth of data to the file
17 f.write('\0'* PAGESIZE)
18 f.write('foo')
19 f.write('\0'* (PAGESIZE-3) )
20 f.flush()
21 m = mmap.mmap(f.fileno(), 2 * PAGESIZE)
22 f.close()
24 # Simple sanity checks
26 print type(m) # SF bug 128713: segfaulted on Linux
27 print ' Position of foo:', m.find('foo') / float(PAGESIZE), 'pages'
28 vereq(m.find('foo'), PAGESIZE)
30 print ' Length of file:', len(m) / float(PAGESIZE), 'pages'
31 vereq(len(m), 2*PAGESIZE)
33 print ' Contents of byte 0:', repr(m[0])
34 vereq(m[0], '\0')
35 print ' Contents of first 3 bytes:', repr(m[0:3])
36 vereq(m[0:3], '\0\0\0')
38 # Modify the file's content
39 print "\n Modifying file's content..."
40 m[0] = '3'
41 m[PAGESIZE +3: PAGESIZE +3+3] = 'bar'
43 # Check that the modification worked
44 print ' Contents of byte 0:', repr(m[0])
45 vereq(m[0], '3')
46 print ' Contents of first 3 bytes:', repr(m[0:3])
47 vereq(m[0:3], '3\0\0')
48 print ' Contents of second page:', repr(m[PAGESIZE-1 : PAGESIZE + 7])
49 vereq(m[PAGESIZE-1 : PAGESIZE + 7], '\0foobar\0')
51 m.flush()
53 # Test doing a regular expression match in an mmap'ed file
54 match = re.search('[A-Za-z]+', m)
55 if match is None:
56 print ' ERROR: regex match on mmap failed!'
57 else:
58 start, end = match.span(0)
59 length = end - start
61 print ' Regex match on mmap (page start, length of match):',
62 print start / float(PAGESIZE), length
64 vereq(start, PAGESIZE)
65 vereq(end, PAGESIZE + 6)
67 # test seeking around (try to overflow the seek implementation)
68 m.seek(0,0)
69 print ' Seek to zeroth byte'
70 vereq(m.tell(), 0)
71 m.seek(42,1)
72 print ' Seek to 42nd byte'
73 vereq(m.tell(), 42)
74 m.seek(0,2)
75 print ' Seek to last byte'
76 vereq(m.tell(), len(m))
78 print ' Try to seek to negative position...'
79 try:
80 m.seek(-1)
81 except ValueError:
82 pass
83 else:
84 verify(0, 'expected a ValueError but did not get it')
86 print ' Try to seek beyond end of mmap...'
87 try:
88 m.seek(1,2)
89 except ValueError:
90 pass
91 else:
92 verify(0, 'expected a ValueError but did not get it')
94 print ' Try to seek to negative position...'
95 try:
96 m.seek(-len(m)-1,2)
97 except ValueError:
98 pass
99 else:
100 verify(0, 'expected a ValueError but did not get it')
102 # Try resizing map
103 print ' Attempting resize()'
104 try:
105 m.resize(512)
106 except SystemError:
107 # resize() not supported
108 # No messages are printed, since the output of this test suite
109 # would then be different across platforms.
110 pass
111 else:
112 # resize() is supported
113 verify(len(m) == 512,
114 "len(m) is %d, but expecting 512" % (len(m),) )
115 # Check that we can no longer seek beyond the new size.
116 try:
117 m.seek(513,0)
118 except ValueError:
119 pass
120 else:
121 verify(0, 'Could seek beyond the new size')
123 m.close()
125 finally:
126 try:
127 f.close()
128 except OSError:
129 pass
130 try:
131 os.unlink(TESTFN)
132 except OSError:
133 pass
135 # Test for "access" keyword parameter
136 try:
137 mapsize = 10
138 print " Creating", mapsize, "byte test data file."
139 open(TESTFN, "wb").write("a"*mapsize)
140 print " Opening mmap with access=ACCESS_READ"
141 f = open(TESTFN, "rb")
142 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_READ)
143 verify(m[:] == 'a'*mapsize, "Readonly memory map data incorrect.")
145 print " Ensuring that readonly mmap can't be slice assigned."
146 try:
147 m[:] = 'b'*mapsize
148 except TypeError:
149 pass
150 else:
151 verify(0, "Able to write to readonly memory map")
153 print " Ensuring that readonly mmap can't be item assigned."
154 try:
155 m[0] = 'b'
156 except TypeError:
157 pass
158 else:
159 verify(0, "Able to write to readonly memory map")
161 print " Ensuring that readonly mmap can't be write() to."
162 try:
163 m.seek(0,0)
164 m.write('abc')
165 except TypeError:
166 pass
167 else:
168 verify(0, "Able to write to readonly memory map")
170 print " Ensuring that readonly mmap can't be write_byte() to."
171 try:
172 m.seek(0,0)
173 m.write_byte('d')
174 except TypeError:
175 pass
176 else:
177 verify(0, "Able to write to readonly memory map")
179 print " Ensuring that readonly mmap can't be resized."
180 try:
181 m.resize(2*mapsize)
182 except SystemError: # resize is not universally supported
183 pass
184 except TypeError:
185 pass
186 else:
187 verify(0, "Able to resize readonly memory map")
188 del m, f
189 verify(open(TESTFN, "rb").read() == 'a'*mapsize,
190 "Readonly memory map data file was modified")
192 print " Opening mmap with size too big"
193 import sys
194 f = open(TESTFN, "r+b")
195 try:
196 m = mmap.mmap(f.fileno(), mapsize+1)
197 except ValueError:
198 # we do not expect a ValueError on Windows
199 # CAUTION: This also changes the size of the file on disk, and
200 # later tests assume that the length hasn't changed. We need to
201 # repair that.
202 if sys.platform.startswith('win'):
203 verify(0, "Opening mmap with size+1 should work on Windows.")
204 else:
205 # we expect a ValueError on Unix, but not on Windows
206 if not sys.platform.startswith('win'):
207 verify(0, "Opening mmap with size+1 should raise ValueError.")
208 m.close()
209 f.close()
210 if sys.platform.startswith('win'):
211 # Repair damage from the resizing test.
212 f = open(TESTFN, 'r+b')
213 f.truncate(mapsize)
214 f.close()
216 print " Opening mmap with access=ACCESS_WRITE"
217 f = open(TESTFN, "r+b")
218 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_WRITE)
219 print " Modifying write-through memory map."
220 m[:] = 'c'*mapsize
221 verify(m[:] == 'c'*mapsize,
222 "Write-through memory map memory not updated properly.")
223 m.flush()
224 m.close()
225 f.close()
226 f = open(TESTFN, 'rb')
227 stuff = f.read()
228 f.close()
229 verify(stuff == 'c'*mapsize,
230 "Write-through memory map data file not updated properly.")
232 print " Opening mmap with access=ACCESS_COPY"
233 f = open(TESTFN, "r+b")
234 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_COPY)
235 print " Modifying copy-on-write memory map."
236 m[:] = 'd'*mapsize
237 verify(m[:] == 'd' * mapsize,
238 "Copy-on-write memory map data not written correctly.")
239 m.flush()
240 verify(open(TESTFN, "rb").read() == 'c'*mapsize,
241 "Copy-on-write test data file should not be modified.")
242 try:
243 print " Ensuring copy-on-write maps cannot be resized."
244 m.resize(2*mapsize)
245 except TypeError:
246 pass
247 else:
248 verify(0, "Copy-on-write mmap resize did not raise exception.")
249 del m, f
250 try:
251 print " Ensuring invalid access parameter raises exception."
252 f = open(TESTFN, "r+b")
253 m = mmap.mmap(f.fileno(), mapsize, access=4)
254 except ValueError:
255 pass
256 else:
257 verify(0, "Invalid access code should have raised exception.")
259 if os.name == "posix":
260 # Try incompatible flags, prot and access parameters.
261 f = open(TESTFN, "r+b")
262 try:
263 m = mmap.mmap(f.fileno(), mapsize, flags=mmap.MAP_PRIVATE,
264 prot=mmap.PROT_READ, access=mmap.ACCESS_WRITE)
265 except ValueError:
266 pass
267 else:
268 verify(0, "Incompatible parameters should raise ValueError.")
269 f.close()
270 finally:
271 try:
272 os.unlink(TESTFN)
273 except OSError:
274 pass
276 # Do a tougher .find() test. SF bug 515943 pointed out that, in 2.2,
277 # searching for data with embedded \0 bytes didn't work.
278 f = open(TESTFN, 'w+')
280 try: # unlink TESTFN no matter what
281 data = 'aabaac\x00deef\x00\x00aa\x00'
282 n = len(data)
283 f.write(data)
284 f.flush()
285 m = mmap.mmap(f.fileno(), n)
286 f.close()
288 for start in range(n+1):
289 for finish in range(start, n+1):
290 slice = data[start : finish]
291 vereq(m.find(slice), data.find(slice))
292 vereq(m.find(slice + 'x'), -1)
293 m.close()
295 finally:
296 os.unlink(TESTFN)
298 # make sure a double close doesn't crash on Solaris (Bug# 665913)
299 f = open(TESTFN, 'w+')
301 try: # unlink TESTFN no matter what
302 f.write(2**16 * 'a') # Arbitrary character
303 f.close()
305 f = open(TESTFN)
306 mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ)
307 mf.close()
308 mf.close()
309 f.close()
311 finally:
312 os.unlink(TESTFN)
315 print ' Test passed'
317 test_both()