blob: 8f20d9696615808017900952e3a6ce5f3bb9bf6a [file] [log] [blame]
R. David Murraya21e4ca2009-03-31 23:16:50 +00001from test.support import TESTFN, run_unittest, import_module
Thomas Wouters89f507f2006-12-13 04:49:30 +00002import unittest
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +00003import os
4import re
5import itertools
6import socket
7import sys
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +00008
R. David Murraya21e4ca2009-03-31 23:16:50 +00009# Skip test if we can't import mmap.
10mmap = import_module('mmap')
11
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +000012PAGESIZE = mmap.PAGESIZE
13
Thomas Wouters89f507f2006-12-13 04:49:30 +000014class MmapTests(unittest.TestCase):
Fred Drake004d5e62000-10-23 17:22:08 +000015
Thomas Wouters89f507f2006-12-13 04:49:30 +000016 def setUp(self):
17 if os.path.exists(TESTFN):
18 os.unlink(TESTFN)
Fred Drake004d5e62000-10-23 17:22:08 +000019
Thomas Wouters89f507f2006-12-13 04:49:30 +000020 def tearDown(self):
Tim Petersfd692082001-05-10 20:03:04 +000021 try:
Fred Drake62787992001-05-11 14:29:21 +000022 os.unlink(TESTFN)
Tim Petersfd692082001-05-10 20:03:04 +000023 except OSError:
24 pass
25
Thomas Wouters89f507f2006-12-13 04:49:30 +000026 def test_basic(self):
27 # Test mmap module on Unix systems and Windows
28
29 # Create a file to be mmap'ed.
Guido van Rossumb358a2c2007-07-16 19:29:02 +000030 f = open(TESTFN, 'bw+')
Thomas Wouters89f507f2006-12-13 04:49:30 +000031 try:
32 # Write 2 pages worth of data to the file
Guido van Rossumb358a2c2007-07-16 19:29:02 +000033 f.write(b'\0'* PAGESIZE)
34 f.write(b'foo')
35 f.write(b'\0'* (PAGESIZE-3) )
Thomas Wouters89f507f2006-12-13 04:49:30 +000036 f.flush()
37 m = mmap.mmap(f.fileno(), 2 * PAGESIZE)
Guido van Rossum456fe5d2007-07-16 19:42:05 +000038 finally:
Thomas Wouters89f507f2006-12-13 04:49:30 +000039 f.close()
40
Guido van Rossum456fe5d2007-07-16 19:42:05 +000041 # Simple sanity checks
Thomas Wouters89f507f2006-12-13 04:49:30 +000042
Guido van Rossum456fe5d2007-07-16 19:42:05 +000043 tp = str(type(m)) # SF bug 128713: segfaulted on Linux
Benjamin Petersone099b372009-04-04 17:09:35 +000044 self.assertEqual(m.find(b'foo'), PAGESIZE)
Thomas Wouters89f507f2006-12-13 04:49:30 +000045
Guido van Rossum456fe5d2007-07-16 19:42:05 +000046 self.assertEqual(len(m), 2*PAGESIZE)
Thomas Wouters89f507f2006-12-13 04:49:30 +000047
Guido van Rossum98297ee2007-11-06 21:34:58 +000048 self.assertEqual(m[0], 0)
Guido van Rossum456fe5d2007-07-16 19:42:05 +000049 self.assertEqual(m[0:3], b'\0\0\0')
Thomas Wouters89f507f2006-12-13 04:49:30 +000050
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +000051 # Shouldn't crash on boundary (Issue #5292)
52 self.assertRaises(IndexError, m.__getitem__, len(m))
53 self.assertRaises(IndexError, m.__setitem__, len(m), b'\0')
54
Guido van Rossum456fe5d2007-07-16 19:42:05 +000055 # Modify the file's content
Guido van Rossum98297ee2007-11-06 21:34:58 +000056 m[0] = b'3'[0]
Guido van Rossum456fe5d2007-07-16 19:42:05 +000057 m[PAGESIZE +3: PAGESIZE +3+3] = b'bar'
Thomas Wouters89f507f2006-12-13 04:49:30 +000058
Guido van Rossum456fe5d2007-07-16 19:42:05 +000059 # Check that the modification worked
Guido van Rossum98297ee2007-11-06 21:34:58 +000060 self.assertEqual(m[0], b'3'[0])
Guido van Rossum456fe5d2007-07-16 19:42:05 +000061 self.assertEqual(m[0:3], b'3\0\0')
62 self.assertEqual(m[PAGESIZE-1 : PAGESIZE + 7], b'\0foobar\0')
Thomas Wouters89f507f2006-12-13 04:49:30 +000063
Guido van Rossum456fe5d2007-07-16 19:42:05 +000064 m.flush()
Thomas Wouters89f507f2006-12-13 04:49:30 +000065
Guido van Rossum456fe5d2007-07-16 19:42:05 +000066 # Test doing a regular expression match in an mmap'ed file
Antoine Pitroufd036452008-08-19 17:56:33 +000067 match = re.search(b'[A-Za-z]+', m)
Guido van Rossum456fe5d2007-07-16 19:42:05 +000068 if match is None:
69 self.fail('regex match on mmap failed!')
70 else:
71 start, end = match.span(0)
72 length = end - start
Thomas Wouters89f507f2006-12-13 04:49:30 +000073
Guido van Rossum456fe5d2007-07-16 19:42:05 +000074 self.assertEqual(start, PAGESIZE)
75 self.assertEqual(end, PAGESIZE + 6)
Thomas Wouters89f507f2006-12-13 04:49:30 +000076
Guido van Rossum456fe5d2007-07-16 19:42:05 +000077 # test seeking around (try to overflow the seek implementation)
78 m.seek(0,0)
79 self.assertEqual(m.tell(), 0)
80 m.seek(42,1)
81 self.assertEqual(m.tell(), 42)
82 m.seek(0,2)
83 self.assertEqual(m.tell(), len(m))
Thomas Wouters89f507f2006-12-13 04:49:30 +000084
Guido van Rossum456fe5d2007-07-16 19:42:05 +000085 # Try to seek to negative position...
86 self.assertRaises(ValueError, m.seek, -1)
Thomas Wouters89f507f2006-12-13 04:49:30 +000087
Guido van Rossum456fe5d2007-07-16 19:42:05 +000088 # Try to seek beyond end of mmap...
89 self.assertRaises(ValueError, m.seek, 1, 2)
Thomas Wouters89f507f2006-12-13 04:49:30 +000090
Guido van Rossum456fe5d2007-07-16 19:42:05 +000091 # Try to seek to negative position...
92 self.assertRaises(ValueError, m.seek, -len(m)-1, 2)
Thomas Wouters89f507f2006-12-13 04:49:30 +000093
Guido van Rossum456fe5d2007-07-16 19:42:05 +000094 # Try resizing map
95 try:
96 m.resize(512)
97 except SystemError:
98 # resize() not supported
99 # No messages are printed, since the output of this test suite
100 # would then be different across platforms.
101 pass
102 else:
103 # resize() is supported
104 self.assertEqual(len(m), 512)
105 # Check that we can no longer seek beyond the new size.
106 self.assertRaises(ValueError, m.seek, 513, 0)
107
108 # Check that the underlying file is truncated too
109 # (bug #728515)
110 f = open(TESTFN)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000111 try:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000112 f.seek(0, 2)
113 self.assertEqual(f.tell(), 512)
Guido van Rossum456fe5d2007-07-16 19:42:05 +0000114 finally:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000115 f.close()
Guido van Rossum456fe5d2007-07-16 19:42:05 +0000116 self.assertEqual(m.size(), 512)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000117
Guido van Rossum456fe5d2007-07-16 19:42:05 +0000118 m.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +0000119
120 def test_access_parameter(self):
121 # Test for "access" keyword parameter
Tim Peters5ebfd362001-11-13 23:11:19 +0000122 mapsize = 10
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000123 with open(TESTFN, "wb") as fp:
124 fp.write(b"a"*mapsize)
125 with open(TESTFN, "rb") as f:
126 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_READ)
127 self.assertEqual(m[:], b'a'*mapsize, "Readonly memory map data incorrect.")
Tim Peters5ebfd362001-11-13 23:11:19 +0000128
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000129 # Ensuring that readonly mmap can't be slice assigned
130 try:
131 m[:] = b'b'*mapsize
132 except TypeError:
133 pass
134 else:
135 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000136
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000137 # Ensuring that readonly mmap can't be item assigned
138 try:
139 m[0] = b'b'
140 except TypeError:
141 pass
142 else:
143 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000144
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000145 # Ensuring that readonly mmap can't be write() to
146 try:
147 m.seek(0,0)
148 m.write(b'abc')
149 except TypeError:
150 pass
151 else:
152 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000153
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000154 # Ensuring that readonly mmap can't be write_byte() to
155 try:
156 m.seek(0,0)
157 m.write_byte(b'd')
158 except TypeError:
159 pass
160 else:
161 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000162
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000163 # Ensuring that readonly mmap can't be resized
164 try:
165 m.resize(2*mapsize)
166 except SystemError: # resize is not universally supported
167 pass
168 except TypeError:
169 pass
170 else:
171 self.fail("Able to resize readonly memory map")
172 with open(TESTFN, "rb") as fp:
173 self.assertEqual(fp.read(), b'a'*mapsize,
174 "Readonly memory map data file was modified")
Tim Peters5ebfd362001-11-13 23:11:19 +0000175
Thomas Wouters89f507f2006-12-13 04:49:30 +0000176 # Opening mmap with size too big
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000177 with open(TESTFN, "r+b") as f:
178 try:
179 m = mmap.mmap(f.fileno(), mapsize+1)
180 except ValueError:
181 # we do not expect a ValueError on Windows
182 # CAUTION: This also changes the size of the file on disk, and
183 # later tests assume that the length hasn't changed. We need to
184 # repair that.
185 if sys.platform.startswith('win'):
186 self.fail("Opening mmap with size+1 should work on Windows.")
187 else:
188 # we expect a ValueError on Unix, but not on Windows
189 if not sys.platform.startswith('win'):
190 self.fail("Opening mmap with size+1 should raise ValueError.")
191 m.close()
Neal Norwitzb5673922002-09-05 21:48:07 +0000192 if sys.platform.startswith('win'):
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000193 # Repair damage from the resizing test.
194 with open(TESTFN, 'r+b') as f:
195 f.truncate(mapsize)
Neal Norwitzb5673922002-09-05 21:48:07 +0000196
Thomas Wouters89f507f2006-12-13 04:49:30 +0000197 # Opening mmap with access=ACCESS_WRITE
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000198 with open(TESTFN, "r+b") as f:
199 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_WRITE)
200 # Modifying write-through memory map
201 m[:] = b'c'*mapsize
202 self.assertEqual(m[:], b'c'*mapsize,
203 "Write-through memory map memory not updated properly.")
204 m.flush()
205 m.close()
206 with open(TESTFN, 'rb') as f:
207 stuff = f.read()
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000208 self.assertEqual(stuff, b'c'*mapsize,
Tim Peters5ebfd362001-11-13 23:11:19 +0000209 "Write-through memory map data file not updated properly.")
210
Thomas Wouters89f507f2006-12-13 04:49:30 +0000211 # Opening mmap with access=ACCESS_COPY
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000212 with open(TESTFN, "r+b") as f:
213 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_COPY)
214 # Modifying copy-on-write memory map
215 m[:] = b'd'*mapsize
216 self.assertEqual(m[:], b'd' * mapsize,
217 "Copy-on-write memory map data not written correctly.")
218 m.flush()
219 with open(TESTFN, "rb") as fp:
220 self.assertEqual(fp.read(), b'c'*mapsize,
221 "Copy-on-write test data file should not be modified.")
222 # Ensuring copy-on-write maps cannot be resized
223 self.assertRaises(TypeError, m.resize, 2*mapsize)
224 m.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +0000225
226 # Ensuring invalid access parameter raises exception
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000227 with open(TESTFN, "r+b") as f:
228 self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, access=4)
Tim Peters5ebfd362001-11-13 23:11:19 +0000229
230 if os.name == "posix":
Tim Peters00cafa02001-11-13 23:39:47 +0000231 # Try incompatible flags, prot and access parameters.
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000232 with open(TESTFN, "r+b") as f:
233 self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize,
234 flags=mmap.MAP_PRIVATE,
235 prot=mmap.PROT_READ, access=mmap.ACCESS_WRITE)
Tim Peters5ebfd362001-11-13 23:11:19 +0000236
Thomas Wouters89f507f2006-12-13 04:49:30 +0000237 def test_bad_file_desc(self):
238 # Try opening a bad file descriptor...
239 self.assertRaises(mmap.error, mmap.mmap, -2, 4096)
Neal Norwitz3b4fff82006-01-11 08:54:45 +0000240
Thomas Wouters89f507f2006-12-13 04:49:30 +0000241 def test_tougher_find(self):
242 # Do a tougher .find() test. SF bug 515943 pointed out that, in 2.2,
243 # searching for data with embedded \0 bytes didn't work.
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000244 with open(TESTFN, 'wb+') as f:
Tim Petersc9ffa062002-03-08 05:43:32 +0000245
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000246 data = b'aabaac\x00deef\x00\x00aa\x00'
247 n = len(data)
248 f.write(data)
249 f.flush()
250 m = mmap.mmap(f.fileno(), n)
Tim Petersc9ffa062002-03-08 05:43:32 +0000251
252 for start in range(n+1):
253 for finish in range(start, n+1):
254 slice = data[start : finish]
Thomas Wouters89f507f2006-12-13 04:49:30 +0000255 self.assertEqual(m.find(slice), data.find(slice))
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000256 self.assertEqual(m.find(slice + b'x'), -1)
Tim Petersddc82ea2003-01-13 21:38:45 +0000257 m.close()
Tim Petersc9ffa062002-03-08 05:43:32 +0000258
Georg Brandlfceab5a2008-01-19 20:08:23 +0000259 def test_find_end(self):
260 # test the new 'end' parameter works as expected
Benjamin Petersone099b372009-04-04 17:09:35 +0000261 f = open(TESTFN, 'wb+')
262 data = b'one two ones'
Georg Brandlfceab5a2008-01-19 20:08:23 +0000263 n = len(data)
264 f.write(data)
265 f.flush()
266 m = mmap.mmap(f.fileno(), n)
267 f.close()
268
Benjamin Petersone099b372009-04-04 17:09:35 +0000269 self.assertEqual(m.find(b'one'), 0)
270 self.assertEqual(m.find(b'ones'), 8)
271 self.assertEqual(m.find(b'one', 0, -1), 0)
272 self.assertEqual(m.find(b'one', 1), 8)
273 self.assertEqual(m.find(b'one', 1, -1), 8)
274 self.assertEqual(m.find(b'one', 1, -2), -1)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000275
276
277 def test_rfind(self):
278 # test the new 'end' parameter works as expected
Benjamin Petersone099b372009-04-04 17:09:35 +0000279 f = open(TESTFN, 'wb+')
280 data = b'one two ones'
Georg Brandlfceab5a2008-01-19 20:08:23 +0000281 n = len(data)
282 f.write(data)
283 f.flush()
284 m = mmap.mmap(f.fileno(), n)
285 f.close()
286
Benjamin Petersone099b372009-04-04 17:09:35 +0000287 self.assertEqual(m.rfind(b'one'), 8)
288 self.assertEqual(m.rfind(b'one '), 0)
289 self.assertEqual(m.rfind(b'one', 0, -1), 8)
290 self.assertEqual(m.rfind(b'one', 0, -2), 0)
291 self.assertEqual(m.rfind(b'one', 1, -1), 8)
292 self.assertEqual(m.rfind(b'one', 1, -2), -1)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000293
294
Thomas Wouters89f507f2006-12-13 04:49:30 +0000295 def test_double_close(self):
296 # make sure a double close doesn't crash on Solaris (Bug# 665913)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000297 f = open(TESTFN, 'wb+')
Tim Petersc9ffa062002-03-08 05:43:32 +0000298
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000299 f.write(2**16 * b'a') # Arbitrary character
Neal Norwitze604c022003-01-10 20:52:16 +0000300 f.close()
301
302 f = open(TESTFN)
Tim Petersddc82ea2003-01-13 21:38:45 +0000303 mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ)
Neal Norwitze604c022003-01-10 20:52:16 +0000304 mf.close()
305 mf.close()
306 f.close()
307
Thomas Wouters89f507f2006-12-13 04:49:30 +0000308 def test_entire_file(self):
309 # test mapping of entire file by passing 0 for map length
310 if hasattr(os, "stat"):
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000311 f = open(TESTFN, "wb+")
Tim Petersc9ffa062002-03-08 05:43:32 +0000312
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000313 f.write(2**16 * b'm') # Arbitrary character
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000314 f.close()
315
316 f = open(TESTFN, "rb+")
Tim Peterseba28be2005-03-28 01:08:02 +0000317 mf = mmap.mmap(f.fileno(), 0)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000318 self.assertEqual(len(mf), 2**16, "Map size should equal file size.")
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000319 self.assertEqual(mf.read(2**16), 2**16 * b"m")
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000320 mf.close()
321 f.close()
322
Antoine Pitrou85f46152011-01-15 16:17:07 +0000323 def test_length_0_offset(self):
324 # Issue #10916: test mapping of remainder of file by passing 0 for
325 # map length with an offset doesn't cause a segfault.
326 if not hasattr(os, "stat"):
327 self.skipTest("needs os.stat")
Antoine Pitroud0ebc752011-01-15 17:25:58 +0000328 # NOTE: allocation granularity is currently 65536 under Win64,
329 # and therefore the minimum offset alignment.
330 with open(TESTFN, "wb") as f:
331 f.write((65536 * 2) * b'm') # Arbitrary character
Antoine Pitrou85f46152011-01-15 16:17:07 +0000332
333 with open(TESTFN, "rb") as f:
Antoine Pitroud0ebc752011-01-15 17:25:58 +0000334 with mmap.mmap(f.fileno(), 0, offset=65536, access=mmap.ACCESS_READ) as mf:
335 self.assertRaises(IndexError, mf.__getitem__, 80000)
Antoine Pitrou85f46152011-01-15 16:17:07 +0000336
Antoine Pitrou305bc9e2011-01-20 21:07:24 +0000337 def test_length_0_large_offset(self):
338 # Issue #10959: test mapping of a file by passing 0 for
339 # map length with a large offset doesn't cause a segfault.
340 if not hasattr(os, "stat"):
341 self.skipTest("needs os.stat")
342
343 with open(TESTFN, "wb") as f:
344 f.write(115699 * b'm') # Arbitrary character
345
346 with open(TESTFN, "w+b") as f:
347 self.assertRaises(ValueError, mmap.mmap, f.fileno(), 0,
348 offset=2147418112)
349
Thomas Wouters89f507f2006-12-13 04:49:30 +0000350 def test_move(self):
351 # make move works everywhere (64-bit format problem earlier)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000352 f = open(TESTFN, 'wb+')
Tim Peterseba28be2005-03-28 01:08:02 +0000353
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000354 f.write(b"ABCDEabcde") # Arbitrary character
Neal Norwitz8856fb72005-12-18 03:34:22 +0000355 f.flush()
356
357 mf = mmap.mmap(f.fileno(), 10)
358 mf.move(5, 0, 5)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000359 self.assertEqual(mf[:], b"ABCDEABCDE", "Map move should have duplicated front 5")
Neal Norwitz8856fb72005-12-18 03:34:22 +0000360 mf.close()
361 f.close()
362
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000363 # more excessive test
364 data = b"0123456789"
365 for dest in range(len(data)):
366 for src in range(len(data)):
367 for count in range(len(data) - max(dest, src)):
368 expected = data[:dest] + data[src:src+count] + data[dest+count:]
369 m = mmap.mmap(-1, len(data))
370 m[:] = data
371 m.move(dest, src, count)
372 self.assertEqual(m[:], expected)
373 m.close()
374
Hirokazu Yamamoto2ca15012009-03-31 20:43:56 +0000375 # segfault test (Issue 5387)
376 m = mmap.mmap(-1, 100)
377 offsets = [-100, -1, 0, 1, 100]
378 for source, dest, size in itertools.product(offsets, offsets, offsets):
379 try:
380 m.move(source, dest, size)
381 except ValueError:
382 pass
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000383
384 offsets = [(-1, -1, -1), (-1, -1, 0), (-1, 0, -1), (0, -1, -1),
385 (-1, 0, 0), (0, -1, 0), (0, 0, -1)]
386 for source, dest, size in offsets:
387 self.assertRaises(ValueError, m.move, source, dest, size)
388
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000389 m.close()
390
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000391 m = mmap.mmap(-1, 1) # single byte
392 self.assertRaises(ValueError, m.move, 0, 0, 2)
393 self.assertRaises(ValueError, m.move, 1, 0, 1)
394 self.assertRaises(ValueError, m.move, 0, 1, 1)
395 m.move(0, 0, 1)
396 m.move(0, 0, 0)
397
398
Thomas Wouters89f507f2006-12-13 04:49:30 +0000399 def test_anonymous(self):
400 # anonymous mmap.mmap(-1, PAGE)
401 m = mmap.mmap(-1, PAGESIZE)
Guido van Rossum805365e2007-05-07 22:24:25 +0000402 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000403 self.assertEqual(m[x], 0,
404 "anonymously mmap'ed contents should be zero")
Neal Norwitz8856fb72005-12-18 03:34:22 +0000405
Guido van Rossum805365e2007-05-07 22:24:25 +0000406 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000407 b = x & 0xff
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000408 m[x] = b
409 self.assertEqual(m[x], b)
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000410
Thomas Woutersed03b412007-08-28 21:37:11 +0000411 def test_extended_getslice(self):
412 # Test extended slicing by comparing with list slicing.
413 s = bytes(reversed(range(256)))
414 m = mmap.mmap(-1, len(s))
415 m[:] = s
416 self.assertEqual(m[:], s)
417 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
418 for start in indices:
419 for stop in indices:
420 # Skip step 0 (invalid)
421 for step in indices[1:]:
422 self.assertEqual(m[start:stop:step],
423 s[start:stop:step])
424
425 def test_extended_set_del_slice(self):
426 # Test extended slicing by comparing with list slicing.
427 s = bytes(reversed(range(256)))
428 m = mmap.mmap(-1, len(s))
429 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
430 for start in indices:
431 for stop in indices:
432 # Skip invalid step 0
433 for step in indices[1:]:
434 m[:] = s
435 self.assertEqual(m[:], s)
436 L = list(s)
437 # Make sure we have a slice of exactly the right length,
438 # but with different data.
439 data = L[start:stop:step]
440 data = bytes(reversed(data))
441 L[start:stop:step] = data
442 m[start:stop:step] = data
Ezio Melottib3aedd42010-11-20 19:04:17 +0000443 self.assertEqual(m[:], bytes(L))
Thomas Woutersed03b412007-08-28 21:37:11 +0000444
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000445 def make_mmap_file (self, f, halfsize):
446 # Write 2 pages worth of data to the file
447 f.write (b'\0' * halfsize)
448 f.write (b'foo')
449 f.write (b'\0' * (halfsize - 3))
450 f.flush ()
451 return mmap.mmap (f.fileno(), 0)
452
453 def test_offset (self):
454 f = open (TESTFN, 'w+b')
455
456 try: # unlink TESTFN no matter what
457 halfsize = mmap.ALLOCATIONGRANULARITY
458 m = self.make_mmap_file (f, halfsize)
459 m.close ()
460 f.close ()
461
462 mapsize = halfsize * 2
463 # Try invalid offset
464 f = open(TESTFN, "r+b")
465 for offset in [-2, -1, None]:
466 try:
467 m = mmap.mmap(f.fileno(), mapsize, offset=offset)
468 self.assertEqual(0, 1)
469 except (ValueError, TypeError, OverflowError):
470 pass
471 else:
472 self.assertEqual(0, 0)
473 f.close()
474
475 # Try valid offset, hopefully 8192 works on all OSes
476 f = open(TESTFN, "r+b")
477 m = mmap.mmap(f.fileno(), mapsize - halfsize, offset=halfsize)
478 self.assertEqual(m[0:3], b'foo')
479 f.close()
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000480
481 # Try resizing map
482 try:
483 m.resize(512)
484 except SystemError:
485 pass
486 else:
487 # resize() is supported
488 self.assertEqual(len(m), 512)
489 # Check that we can no longer seek beyond the new size.
490 self.assertRaises(ValueError, m.seek, 513, 0)
491 # Check that the content is not changed
492 self.assertEqual(m[0:3], b'foo')
493
494 # Check that the underlying file is truncated too
495 f = open(TESTFN)
496 f.seek(0, 2)
497 self.assertEqual(f.tell(), halfsize + 512)
498 f.close()
499 self.assertEqual(m.size(), halfsize + 512)
500
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000501 m.close()
502
503 finally:
504 f.close()
505 try:
506 os.unlink(TESTFN)
507 except OSError:
508 pass
509
Christian Heimes1af737c2008-01-23 08:24:23 +0000510 def test_subclass(self):
511 class anon_mmap(mmap.mmap):
512 def __new__(klass, *args, **kwargs):
513 return mmap.mmap.__new__(klass, -1, *args, **kwargs)
514 anon_mmap(PAGESIZE)
515
Christian Heimesa156e092008-02-16 07:38:31 +0000516 def test_prot_readonly(self):
Christian Heimes18c66892008-02-17 13:31:39 +0000517 if not hasattr(mmap, 'PROT_READ'):
518 return
Christian Heimesa156e092008-02-16 07:38:31 +0000519 mapsize = 10
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000520 with open(TESTFN, "wb") as fp:
521 fp.write(b"a"*mapsize)
Christian Heimesa156e092008-02-16 07:38:31 +0000522 f = open(TESTFN, "rb")
523 m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ)
524 self.assertRaises(TypeError, m.write, "foo")
Martin v. Löwise1e9f232008-04-01 06:17:46 +0000525 f.close()
Christian Heimes1af737c2008-01-23 08:24:23 +0000526
Christian Heimes7131fd92008-02-19 14:21:46 +0000527 def test_error(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000528 self.assertTrue(issubclass(mmap.error, EnvironmentError))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000529 self.assertIn("mmap.error", str(mmap.error))
Christian Heimes7131fd92008-02-19 14:21:46 +0000530
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000531 def test_io_methods(self):
532 data = b"0123456789"
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000533 with open(TESTFN, "wb") as fp:
534 fp.write(b"x"*len(data))
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000535 f = open(TESTFN, "r+b")
536 m = mmap.mmap(f.fileno(), len(data))
537 f.close()
538 # Test write_byte()
539 for i in range(len(data)):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000540 self.assertEqual(m.tell(), i)
Benjamin Petersone099b372009-04-04 17:09:35 +0000541 m.write_byte(data[i])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000542 self.assertEqual(m.tell(), i+1)
Benjamin Petersone099b372009-04-04 17:09:35 +0000543 self.assertRaises(ValueError, m.write_byte, b"x"[0])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000544 self.assertEqual(m[:], data)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000545 # Test read_byte()
546 m.seek(0)
547 for i in range(len(data)):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000548 self.assertEqual(m.tell(), i)
549 self.assertEqual(m.read_byte(), data[i])
550 self.assertEqual(m.tell(), i+1)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000551 self.assertRaises(ValueError, m.read_byte)
552 # Test read()
553 m.seek(3)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000554 self.assertEqual(m.read(3), b"345")
555 self.assertEqual(m.tell(), 6)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000556 # Test write()
557 m.seek(3)
558 m.write(b"bar")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000559 self.assertEqual(m.tell(), 6)
560 self.assertEqual(m[:], b"012bar6789")
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000561 m.seek(8)
562 self.assertRaises(ValueError, m.write, b"bar")
563
Hirokazu Yamamoto3cdd5cb2010-11-04 12:09:08 +0000564 def test_non_ascii_byte(self):
565 for b in (129, 200, 255): # > 128
566 m = mmap.mmap(-1, 1)
567 m.write_byte(b)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000568 self.assertEqual(m[0], b)
Hirokazu Yamamoto3cdd5cb2010-11-04 12:09:08 +0000569 m.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000570 self.assertEqual(m.read_byte(), b)
Hirokazu Yamamoto3cdd5cb2010-11-04 12:09:08 +0000571 m.close()
572
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000573 if os.name == 'nt':
574 def test_tagname(self):
575 data1 = b"0123456789"
576 data2 = b"abcdefghij"
577 assert len(data1) == len(data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000578
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000579 # Test same tag
580 m1 = mmap.mmap(-1, len(data1), tagname="foo")
581 m1[:] = data1
582 m2 = mmap.mmap(-1, len(data2), tagname="foo")
583 m2[:] = data2
Ezio Melottib3aedd42010-11-20 19:04:17 +0000584 self.assertEqual(m1[:], data2)
585 self.assertEqual(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000586 m2.close()
587 m1.close()
588
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000589 # Test differnt tag
590 m1 = mmap.mmap(-1, len(data1), tagname="foo")
591 m1[:] = data1
592 m2 = mmap.mmap(-1, len(data2), tagname="boo")
593 m2[:] = data2
Ezio Melottib3aedd42010-11-20 19:04:17 +0000594 self.assertEqual(m1[:], data1)
595 self.assertEqual(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000596 m2.close()
597 m1.close()
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000598
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000599 def test_crasher_on_windows(self):
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000600 # Should not crash (Issue 1733986)
601 m = mmap.mmap(-1, 1000, tagname="foo")
602 try:
603 mmap.mmap(-1, 5000, tagname="foo")[:] # same tagname, but larger size
604 except:
605 pass
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000606 m.close()
607
608 # Should not crash (Issue 5385)
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000609 with open(TESTFN, "wb") as fp:
610 fp.write(b"x"*10)
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000611 f = open(TESTFN, "r+b")
612 m = mmap.mmap(f.fileno(), 0)
613 f.close()
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000614 try:
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000615 m.resize(0) # will raise WindowsError
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000616 except:
617 pass
618 try:
619 m[:]
620 except:
621 pass
622 m.close()
623
Brian Curtinea47eaa2010-08-01 15:26:26 +0000624 def test_invalid_descriptor(self):
625 # socket file descriptors are valid, but out of range
626 # for _get_osfhandle, causing a crash when validating the
627 # parameters to _get_osfhandle.
628 s = socket.socket()
629 try:
630 with self.assertRaises(mmap.error):
631 m = mmap.mmap(s.fileno(), 10)
632 finally:
633 s.close()
634
Georg Brandl0bccc182010-08-01 14:50:00 +0000635 def test_context_manager(self):
636 with mmap.mmap(-1, 10) as m:
637 self.assertFalse(m.closed)
638 self.assertTrue(m.closed)
639
640 def test_context_manager_exception(self):
641 # Test that the IOError gets passed through
642 with self.assertRaises(Exception) as exc:
643 with mmap.mmap(-1, 10) as m:
644 raise IOError
645 self.assertIsInstance(exc.exception, IOError,
646 "wrong exception raised in context manager")
647 self.assertTrue(m.closed, "context manager failed")
648
Christian Heimes7131fd92008-02-19 14:21:46 +0000649
Thomas Wouters89f507f2006-12-13 04:49:30 +0000650def test_main():
651 run_unittest(MmapTests)
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +0000652
Thomas Wouters89f507f2006-12-13 04:49:30 +0000653if __name__ == '__main__':
654 test_main()