blob: 7c51085a997c40d32c975109f16d18941811a534 [file] [log] [blame]
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001from test.support import TESTFN, run_unittest, import_module, unlink, requires
Thomas Wouters89f507f2006-12-13 04:49:30 +00002import unittest
Antoine Pitrou9e719b62011-02-28 23:48:16 +00003import os, re, itertools, socket, sys
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +00004
R. David Murraya21e4ca2009-03-31 23:16:50 +00005# Skip test if we can't import mmap.
6mmap = import_module('mmap')
7
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +00008PAGESIZE = mmap.PAGESIZE
9
Thomas Wouters89f507f2006-12-13 04:49:30 +000010class MmapTests(unittest.TestCase):
Fred Drake004d5e62000-10-23 17:22:08 +000011
Thomas Wouters89f507f2006-12-13 04:49:30 +000012 def setUp(self):
13 if os.path.exists(TESTFN):
14 os.unlink(TESTFN)
Fred Drake004d5e62000-10-23 17:22:08 +000015
Thomas Wouters89f507f2006-12-13 04:49:30 +000016 def tearDown(self):
Tim Petersfd692082001-05-10 20:03:04 +000017 try:
Fred Drake62787992001-05-11 14:29:21 +000018 os.unlink(TESTFN)
Tim Petersfd692082001-05-10 20:03:04 +000019 except OSError:
20 pass
21
Thomas Wouters89f507f2006-12-13 04:49:30 +000022 def test_basic(self):
23 # Test mmap module on Unix systems and Windows
24
25 # Create a file to be mmap'ed.
Guido van Rossumb358a2c2007-07-16 19:29:02 +000026 f = open(TESTFN, 'bw+')
Thomas Wouters89f507f2006-12-13 04:49:30 +000027 try:
28 # Write 2 pages worth of data to the file
Guido van Rossumb358a2c2007-07-16 19:29:02 +000029 f.write(b'\0'* PAGESIZE)
30 f.write(b'foo')
31 f.write(b'\0'* (PAGESIZE-3) )
Thomas Wouters89f507f2006-12-13 04:49:30 +000032 f.flush()
33 m = mmap.mmap(f.fileno(), 2 * PAGESIZE)
Guido van Rossum456fe5d2007-07-16 19:42:05 +000034 finally:
Thomas Wouters89f507f2006-12-13 04:49:30 +000035 f.close()
36
Guido van Rossum456fe5d2007-07-16 19:42:05 +000037 # Simple sanity checks
Thomas Wouters89f507f2006-12-13 04:49:30 +000038
Guido van Rossum456fe5d2007-07-16 19:42:05 +000039 tp = str(type(m)) # SF bug 128713: segfaulted on Linux
Benjamin Petersone099b372009-04-04 17:09:35 +000040 self.assertEqual(m.find(b'foo'), PAGESIZE)
Thomas Wouters89f507f2006-12-13 04:49:30 +000041
Guido van Rossum456fe5d2007-07-16 19:42:05 +000042 self.assertEqual(len(m), 2*PAGESIZE)
Thomas Wouters89f507f2006-12-13 04:49:30 +000043
Guido van Rossum98297ee2007-11-06 21:34:58 +000044 self.assertEqual(m[0], 0)
Guido van Rossum456fe5d2007-07-16 19:42:05 +000045 self.assertEqual(m[0:3], b'\0\0\0')
Thomas Wouters89f507f2006-12-13 04:49:30 +000046
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +000047 # Shouldn't crash on boundary (Issue #5292)
48 self.assertRaises(IndexError, m.__getitem__, len(m))
49 self.assertRaises(IndexError, m.__setitem__, len(m), b'\0')
50
Guido van Rossum456fe5d2007-07-16 19:42:05 +000051 # Modify the file's content
Guido van Rossum98297ee2007-11-06 21:34:58 +000052 m[0] = b'3'[0]
Guido van Rossum456fe5d2007-07-16 19:42:05 +000053 m[PAGESIZE +3: PAGESIZE +3+3] = b'bar'
Thomas Wouters89f507f2006-12-13 04:49:30 +000054
Guido van Rossum456fe5d2007-07-16 19:42:05 +000055 # Check that the modification worked
Guido van Rossum98297ee2007-11-06 21:34:58 +000056 self.assertEqual(m[0], b'3'[0])
Guido van Rossum456fe5d2007-07-16 19:42:05 +000057 self.assertEqual(m[0:3], b'3\0\0')
58 self.assertEqual(m[PAGESIZE-1 : PAGESIZE + 7], b'\0foobar\0')
Thomas Wouters89f507f2006-12-13 04:49:30 +000059
Guido van Rossum456fe5d2007-07-16 19:42:05 +000060 m.flush()
Thomas Wouters89f507f2006-12-13 04:49:30 +000061
Guido van Rossum456fe5d2007-07-16 19:42:05 +000062 # Test doing a regular expression match in an mmap'ed file
Antoine Pitroufd036452008-08-19 17:56:33 +000063 match = re.search(b'[A-Za-z]+', m)
Guido van Rossum456fe5d2007-07-16 19:42:05 +000064 if match is None:
65 self.fail('regex match on mmap failed!')
66 else:
67 start, end = match.span(0)
68 length = end - start
Thomas Wouters89f507f2006-12-13 04:49:30 +000069
Guido van Rossum456fe5d2007-07-16 19:42:05 +000070 self.assertEqual(start, PAGESIZE)
71 self.assertEqual(end, PAGESIZE + 6)
Thomas Wouters89f507f2006-12-13 04:49:30 +000072
Guido van Rossum456fe5d2007-07-16 19:42:05 +000073 # test seeking around (try to overflow the seek implementation)
74 m.seek(0,0)
75 self.assertEqual(m.tell(), 0)
76 m.seek(42,1)
77 self.assertEqual(m.tell(), 42)
78 m.seek(0,2)
79 self.assertEqual(m.tell(), len(m))
Thomas Wouters89f507f2006-12-13 04:49:30 +000080
Guido van Rossum456fe5d2007-07-16 19:42:05 +000081 # Try to seek to negative position...
82 self.assertRaises(ValueError, m.seek, -1)
Thomas Wouters89f507f2006-12-13 04:49:30 +000083
Guido van Rossum456fe5d2007-07-16 19:42:05 +000084 # Try to seek beyond end of mmap...
85 self.assertRaises(ValueError, m.seek, 1, 2)
Thomas Wouters89f507f2006-12-13 04:49:30 +000086
Guido van Rossum456fe5d2007-07-16 19:42:05 +000087 # Try to seek to negative position...
88 self.assertRaises(ValueError, m.seek, -len(m)-1, 2)
Thomas Wouters89f507f2006-12-13 04:49:30 +000089
Guido van Rossum456fe5d2007-07-16 19:42:05 +000090 # Try resizing map
91 try:
92 m.resize(512)
93 except SystemError:
94 # resize() not supported
95 # No messages are printed, since the output of this test suite
96 # would then be different across platforms.
97 pass
98 else:
99 # resize() is supported
100 self.assertEqual(len(m), 512)
101 # Check that we can no longer seek beyond the new size.
102 self.assertRaises(ValueError, m.seek, 513, 0)
103
104 # Check that the underlying file is truncated too
105 # (bug #728515)
106 f = open(TESTFN)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000107 try:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000108 f.seek(0, 2)
109 self.assertEqual(f.tell(), 512)
Guido van Rossum456fe5d2007-07-16 19:42:05 +0000110 finally:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000111 f.close()
Guido van Rossum456fe5d2007-07-16 19:42:05 +0000112 self.assertEqual(m.size(), 512)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000113
Guido van Rossum456fe5d2007-07-16 19:42:05 +0000114 m.close()
Thomas Wouters89f507f2006-12-13 04:49:30 +0000115
116 def test_access_parameter(self):
117 # Test for "access" keyword parameter
Tim Peters5ebfd362001-11-13 23:11:19 +0000118 mapsize = 10
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000119 open(TESTFN, "wb").write(b"a"*mapsize)
Tim Peters5ebfd362001-11-13 23:11:19 +0000120 f = open(TESTFN, "rb")
121 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_READ)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000122 self.assertEqual(m[:], b'a'*mapsize, "Readonly memory map data incorrect.")
Tim Peters5ebfd362001-11-13 23:11:19 +0000123
Thomas Wouters89f507f2006-12-13 04:49:30 +0000124 # Ensuring that readonly mmap can't be slice assigned
Tim Peters5ebfd362001-11-13 23:11:19 +0000125 try:
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000126 m[:] = b'b'*mapsize
Tim Peters5ebfd362001-11-13 23:11:19 +0000127 except TypeError:
128 pass
129 else:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000130 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000131
Thomas Wouters89f507f2006-12-13 04:49:30 +0000132 # Ensuring that readonly mmap can't be item assigned
Tim Peters5ebfd362001-11-13 23:11:19 +0000133 try:
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000134 m[0] = b'b'
Tim Peters5ebfd362001-11-13 23:11:19 +0000135 except TypeError:
136 pass
137 else:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000138 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000139
Thomas Wouters89f507f2006-12-13 04:49:30 +0000140 # Ensuring that readonly mmap can't be write() to
Tim Peters5ebfd362001-11-13 23:11:19 +0000141 try:
142 m.seek(0,0)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000143 m.write(b'abc')
Tim Peters5ebfd362001-11-13 23:11:19 +0000144 except TypeError:
145 pass
146 else:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000147 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000148
Thomas Wouters89f507f2006-12-13 04:49:30 +0000149 # Ensuring that readonly mmap can't be write_byte() to
Tim Peters5ebfd362001-11-13 23:11:19 +0000150 try:
151 m.seek(0,0)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000152 m.write_byte(b'd')
Tim Peters5ebfd362001-11-13 23:11:19 +0000153 except TypeError:
154 pass
155 else:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000156 self.fail("Able to write to readonly memory map")
Tim Peters5ebfd362001-11-13 23:11:19 +0000157
Thomas Wouters89f507f2006-12-13 04:49:30 +0000158 # Ensuring that readonly mmap can't be resized
Tim Peters5ebfd362001-11-13 23:11:19 +0000159 try:
160 m.resize(2*mapsize)
161 except SystemError: # resize is not universally supported
162 pass
163 except TypeError:
164 pass
165 else:
Thomas Wouters89f507f2006-12-13 04:49:30 +0000166 self.fail("Able to resize readonly memory map")
Martin v. Löwise1e9f232008-04-01 06:17:46 +0000167 f.close()
Tim Peters5ebfd362001-11-13 23:11:19 +0000168 del m, f
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000169 self.assertEqual(open(TESTFN, "rb").read(), b'a'*mapsize,
Tim Peters5ebfd362001-11-13 23:11:19 +0000170 "Readonly memory map data file was modified")
171
Thomas Wouters89f507f2006-12-13 04:49:30 +0000172 # Opening mmap with size too big
Neal Norwitzb5673922002-09-05 21:48:07 +0000173 import sys
174 f = open(TESTFN, "r+b")
175 try:
176 m = mmap.mmap(f.fileno(), mapsize+1)
177 except ValueError:
178 # we do not expect a ValueError on Windows
Tim Peters4f4f4d72002-09-10 20:49:15 +0000179 # CAUTION: This also changes the size of the file on disk, and
180 # later tests assume that the length hasn't changed. We need to
181 # repair that.
Neal Norwitzb5673922002-09-05 21:48:07 +0000182 if sys.platform.startswith('win'):
Thomas Wouters89f507f2006-12-13 04:49:30 +0000183 self.fail("Opening mmap with size+1 should work on Windows.")
Neal Norwitzb5673922002-09-05 21:48:07 +0000184 else:
185 # we expect a ValueError on Unix, but not on Windows
186 if not sys.platform.startswith('win'):
Thomas Wouters89f507f2006-12-13 04:49:30 +0000187 self.fail("Opening mmap with size+1 should raise ValueError.")
Barry Warsawccd9e752002-09-11 02:56:42 +0000188 m.close()
Tim Peters4f4f4d72002-09-10 20:49:15 +0000189 f.close()
190 if sys.platform.startswith('win'):
191 # Repair damage from the resizing test.
192 f = open(TESTFN, 'r+b')
193 f.truncate(mapsize)
194 f.close()
Neal Norwitzb5673922002-09-05 21:48:07 +0000195
Thomas Wouters89f507f2006-12-13 04:49:30 +0000196 # Opening mmap with access=ACCESS_WRITE
Tim Peters5ebfd362001-11-13 23:11:19 +0000197 f = open(TESTFN, "r+b")
198 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_WRITE)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000199 # Modifying write-through memory map
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000200 m[:] = b'c'*mapsize
201 self.assertEqual(m[:], b'c'*mapsize,
Tim Peters5ebfd362001-11-13 23:11:19 +0000202 "Write-through memory map memory not updated properly.")
203 m.flush()
Tim Peters1b5112a2002-09-10 21:19:55 +0000204 m.close()
205 f.close()
Tim Peters4f4f4d72002-09-10 20:49:15 +0000206 f = open(TESTFN, 'rb')
207 stuff = f.read()
208 f.close()
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000209 self.assertEqual(stuff, b'c'*mapsize,
Tim Peters5ebfd362001-11-13 23:11:19 +0000210 "Write-through memory map data file not updated properly.")
211
Thomas Wouters89f507f2006-12-13 04:49:30 +0000212 # Opening mmap with access=ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +0000213 f = open(TESTFN, "r+b")
214 m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_COPY)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000215 # Modifying copy-on-write memory map
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000216 m[:] = b'd'*mapsize
217 self.assertEqual(m[:], b'd' * mapsize,
Tim Peters5ebfd362001-11-13 23:11:19 +0000218 "Copy-on-write memory map data not written correctly.")
219 m.flush()
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000220 self.assertEqual(open(TESTFN, "rb").read(), b'c'*mapsize,
Tim Peters5ebfd362001-11-13 23:11:19 +0000221 "Copy-on-write test data file should not be modified.")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000222 # Ensuring copy-on-write maps cannot be resized
223 self.assertRaises(TypeError, m.resize, 2*mapsize)
Martin v. Löwise1e9f232008-04-01 06:17:46 +0000224 f.close()
Tim Peters5ebfd362001-11-13 23:11:19 +0000225 del m, f
Thomas Wouters89f507f2006-12-13 04:49:30 +0000226
227 # Ensuring invalid access parameter raises exception
228 f = open(TESTFN, "r+b")
229 self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, access=4)
230 f.close()
Tim Peters5ebfd362001-11-13 23:11:19 +0000231
232 if os.name == "posix":
Tim Peters00cafa02001-11-13 23:39:47 +0000233 # Try incompatible flags, prot and access parameters.
234 f = open(TESTFN, "r+b")
Thomas Wouters89f507f2006-12-13 04:49:30 +0000235 self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize,
236 flags=mmap.MAP_PRIVATE,
Tim Peters5ebfd362001-11-13 23:11:19 +0000237 prot=mmap.PROT_READ, access=mmap.ACCESS_WRITE)
Tim Peters5379dea2002-04-18 04:30:18 +0000238 f.close()
Tim Peters5ebfd362001-11-13 23:11:19 +0000239
Antoine Pitrou7b50c2c2011-03-06 01:47:18 +0100240 # Try writing with PROT_EXEC and without PROT_WRITE
241 prot = mmap.PROT_READ | getattr(mmap, 'PROT_EXEC', 0)
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +0100242 with open(TESTFN, "r+b") as f:
Antoine Pitrou7b50c2c2011-03-06 01:47:18 +0100243 m = mmap.mmap(f.fileno(), mapsize, prot=prot)
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +0100244 self.assertRaises(TypeError, m.write, b"abcdef")
245 self.assertRaises(TypeError, m.write_byte, 0)
246 m.close()
247
Thomas Wouters89f507f2006-12-13 04:49:30 +0000248 def test_bad_file_desc(self):
249 # Try opening a bad file descriptor...
250 self.assertRaises(mmap.error, mmap.mmap, -2, 4096)
Neal Norwitz3b4fff82006-01-11 08:54:45 +0000251
Thomas Wouters89f507f2006-12-13 04:49:30 +0000252 def test_tougher_find(self):
253 # Do a tougher .find() test. SF bug 515943 pointed out that, in 2.2,
254 # searching for data with embedded \0 bytes didn't work.
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000255 f = open(TESTFN, 'wb+')
Tim Petersc9ffa062002-03-08 05:43:32 +0000256
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000257 data = b'aabaac\x00deef\x00\x00aa\x00'
Tim Petersc9ffa062002-03-08 05:43:32 +0000258 n = len(data)
259 f.write(data)
Tim Peters5379dea2002-04-18 04:30:18 +0000260 f.flush()
Tim Petersc9ffa062002-03-08 05:43:32 +0000261 m = mmap.mmap(f.fileno(), n)
262 f.close()
263
264 for start in range(n+1):
265 for finish in range(start, n+1):
266 slice = data[start : finish]
Thomas Wouters89f507f2006-12-13 04:49:30 +0000267 self.assertEqual(m.find(slice), data.find(slice))
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000268 self.assertEqual(m.find(slice + b'x'), -1)
Tim Petersddc82ea2003-01-13 21:38:45 +0000269 m.close()
Tim Petersc9ffa062002-03-08 05:43:32 +0000270
Georg Brandlfceab5a2008-01-19 20:08:23 +0000271 def test_find_end(self):
272 # test the new 'end' parameter works as expected
Benjamin Petersone099b372009-04-04 17:09:35 +0000273 f = open(TESTFN, 'wb+')
274 data = b'one two ones'
Georg Brandlfceab5a2008-01-19 20:08:23 +0000275 n = len(data)
276 f.write(data)
277 f.flush()
278 m = mmap.mmap(f.fileno(), n)
279 f.close()
280
Benjamin Petersone099b372009-04-04 17:09:35 +0000281 self.assertEqual(m.find(b'one'), 0)
282 self.assertEqual(m.find(b'ones'), 8)
283 self.assertEqual(m.find(b'one', 0, -1), 0)
284 self.assertEqual(m.find(b'one', 1), 8)
285 self.assertEqual(m.find(b'one', 1, -1), 8)
286 self.assertEqual(m.find(b'one', 1, -2), -1)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000287
288
289 def test_rfind(self):
290 # test the new 'end' parameter works as expected
Benjamin Petersone099b372009-04-04 17:09:35 +0000291 f = open(TESTFN, 'wb+')
292 data = b'one two ones'
Georg Brandlfceab5a2008-01-19 20:08:23 +0000293 n = len(data)
294 f.write(data)
295 f.flush()
296 m = mmap.mmap(f.fileno(), n)
297 f.close()
298
Benjamin Petersone099b372009-04-04 17:09:35 +0000299 self.assertEqual(m.rfind(b'one'), 8)
300 self.assertEqual(m.rfind(b'one '), 0)
301 self.assertEqual(m.rfind(b'one', 0, -1), 8)
302 self.assertEqual(m.rfind(b'one', 0, -2), 0)
303 self.assertEqual(m.rfind(b'one', 1, -1), 8)
304 self.assertEqual(m.rfind(b'one', 1, -2), -1)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000305
306
Thomas Wouters89f507f2006-12-13 04:49:30 +0000307 def test_double_close(self):
308 # make sure a double close doesn't crash on Solaris (Bug# 665913)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000309 f = open(TESTFN, 'wb+')
Tim Petersc9ffa062002-03-08 05:43:32 +0000310
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000311 f.write(2**16 * b'a') # Arbitrary character
Neal Norwitze604c022003-01-10 20:52:16 +0000312 f.close()
313
314 f = open(TESTFN)
Tim Petersddc82ea2003-01-13 21:38:45 +0000315 mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ)
Neal Norwitze604c022003-01-10 20:52:16 +0000316 mf.close()
317 mf.close()
318 f.close()
319
Thomas Wouters89f507f2006-12-13 04:49:30 +0000320 def test_entire_file(self):
321 # test mapping of entire file by passing 0 for map length
322 if hasattr(os, "stat"):
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000323 f = open(TESTFN, "wb+")
Tim Petersc9ffa062002-03-08 05:43:32 +0000324
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000325 f.write(2**16 * b'm') # Arbitrary character
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000326 f.close()
327
328 f = open(TESTFN, "rb+")
Tim Peterseba28be2005-03-28 01:08:02 +0000329 mf = mmap.mmap(f.fileno(), 0)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000330 self.assertEqual(len(mf), 2**16, "Map size should equal file size.")
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000331 self.assertEqual(mf.read(2**16), 2**16 * b"m")
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000332 mf.close()
333 f.close()
334
Antoine Pitroufb7bc3d2011-01-15 16:18:37 +0000335 def test_length_0_offset(self):
336 # Issue #10916: test mapping of remainder of file by passing 0 for
337 # map length with an offset doesn't cause a segfault.
338 if not hasattr(os, "stat"):
339 self.skipTest("needs os.stat")
Antoine Pitrou50dc65f2011-01-15 17:31:19 +0000340 # NOTE: allocation granularity is currently 65536 under Win64,
341 # and therefore the minimum offset alignment.
342 with open(TESTFN, "wb") as f:
343 f.write((65536 * 2) * b'm') # Arbitrary character
Antoine Pitroufb7bc3d2011-01-15 16:18:37 +0000344
345 with open(TESTFN, "rb") as f:
Antoine Pitrou50dc65f2011-01-15 17:31:19 +0000346 mf = mmap.mmap(f.fileno(), 0, offset=65536, access=mmap.ACCESS_READ)
347 try:
348 self.assertRaises(IndexError, mf.__getitem__, 80000)
349 finally:
350 mf.close()
Antoine Pitroufb7bc3d2011-01-15 16:18:37 +0000351
Antoine Pitrou6107a4e2011-01-20 21:11:13 +0000352 def test_length_0_large_offset(self):
353 # Issue #10959: test mapping of a file by passing 0 for
354 # map length with a large offset doesn't cause a segfault.
355 if not hasattr(os, "stat"):
356 self.skipTest("needs os.stat")
357
358 with open(TESTFN, "wb") as f:
359 f.write(115699 * b'm') # Arbitrary character
360
361 with open(TESTFN, "w+b") as f:
362 self.assertRaises(ValueError, mmap.mmap, f.fileno(), 0,
363 offset=2147418112)
364
Thomas Wouters89f507f2006-12-13 04:49:30 +0000365 def test_move(self):
366 # make move works everywhere (64-bit format problem earlier)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000367 f = open(TESTFN, 'wb+')
Tim Peterseba28be2005-03-28 01:08:02 +0000368
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000369 f.write(b"ABCDEabcde") # Arbitrary character
Neal Norwitz8856fb72005-12-18 03:34:22 +0000370 f.flush()
371
372 mf = mmap.mmap(f.fileno(), 10)
373 mf.move(5, 0, 5)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000374 self.assertEqual(mf[:], b"ABCDEABCDE", "Map move should have duplicated front 5")
Neal Norwitz8856fb72005-12-18 03:34:22 +0000375 mf.close()
376 f.close()
377
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000378 # more excessive test
379 data = b"0123456789"
380 for dest in range(len(data)):
381 for src in range(len(data)):
382 for count in range(len(data) - max(dest, src)):
383 expected = data[:dest] + data[src:src+count] + data[dest+count:]
384 m = mmap.mmap(-1, len(data))
385 m[:] = data
386 m.move(dest, src, count)
387 self.assertEqual(m[:], expected)
388 m.close()
389
Hirokazu Yamamoto2ca15012009-03-31 20:43:56 +0000390 # segfault test (Issue 5387)
391 m = mmap.mmap(-1, 100)
392 offsets = [-100, -1, 0, 1, 100]
393 for source, dest, size in itertools.product(offsets, offsets, offsets):
394 try:
395 m.move(source, dest, size)
396 except ValueError:
397 pass
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000398
399 offsets = [(-1, -1, -1), (-1, -1, 0), (-1, 0, -1), (0, -1, -1),
400 (-1, 0, 0), (0, -1, 0), (0, 0, -1)]
401 for source, dest, size in offsets:
402 self.assertRaises(ValueError, m.move, source, dest, size)
403
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000404 m.close()
405
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000406 m = mmap.mmap(-1, 1) # single byte
407 self.assertRaises(ValueError, m.move, 0, 0, 2)
408 self.assertRaises(ValueError, m.move, 1, 0, 1)
409 self.assertRaises(ValueError, m.move, 0, 1, 1)
410 m.move(0, 0, 1)
411 m.move(0, 0, 0)
412
413
Thomas Wouters89f507f2006-12-13 04:49:30 +0000414 def test_anonymous(self):
415 # anonymous mmap.mmap(-1, PAGE)
416 m = mmap.mmap(-1, PAGESIZE)
Guido van Rossum805365e2007-05-07 22:24:25 +0000417 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000418 self.assertEqual(m[x], 0,
419 "anonymously mmap'ed contents should be zero")
Neal Norwitz8856fb72005-12-18 03:34:22 +0000420
Guido van Rossum805365e2007-05-07 22:24:25 +0000421 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000422 b = x & 0xff
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000423 m[x] = b
424 self.assertEqual(m[x], b)
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000425
Thomas Woutersed03b412007-08-28 21:37:11 +0000426 def test_extended_getslice(self):
427 # Test extended slicing by comparing with list slicing.
428 s = bytes(reversed(range(256)))
429 m = mmap.mmap(-1, len(s))
430 m[:] = s
431 self.assertEqual(m[:], s)
432 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
433 for start in indices:
434 for stop in indices:
435 # Skip step 0 (invalid)
436 for step in indices[1:]:
437 self.assertEqual(m[start:stop:step],
438 s[start:stop:step])
439
440 def test_extended_set_del_slice(self):
441 # Test extended slicing by comparing with list slicing.
442 s = bytes(reversed(range(256)))
443 m = mmap.mmap(-1, len(s))
444 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
445 for start in indices:
446 for stop in indices:
447 # Skip invalid step 0
448 for step in indices[1:]:
449 m[:] = s
450 self.assertEqual(m[:], s)
451 L = list(s)
452 # Make sure we have a slice of exactly the right length,
453 # but with different data.
454 data = L[start:stop:step]
455 data = bytes(reversed(data))
456 L[start:stop:step] = data
457 m[start:stop:step] = data
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000458 self.assertEqual(m[:], bytes(L))
Thomas Woutersed03b412007-08-28 21:37:11 +0000459
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000460 def make_mmap_file (self, f, halfsize):
461 # Write 2 pages worth of data to the file
462 f.write (b'\0' * halfsize)
463 f.write (b'foo')
464 f.write (b'\0' * (halfsize - 3))
465 f.flush ()
466 return mmap.mmap (f.fileno(), 0)
467
468 def test_offset (self):
469 f = open (TESTFN, 'w+b')
470
471 try: # unlink TESTFN no matter what
472 halfsize = mmap.ALLOCATIONGRANULARITY
473 m = self.make_mmap_file (f, halfsize)
474 m.close ()
475 f.close ()
476
477 mapsize = halfsize * 2
478 # Try invalid offset
479 f = open(TESTFN, "r+b")
480 for offset in [-2, -1, None]:
481 try:
482 m = mmap.mmap(f.fileno(), mapsize, offset=offset)
483 self.assertEqual(0, 1)
484 except (ValueError, TypeError, OverflowError):
485 pass
486 else:
487 self.assertEqual(0, 0)
488 f.close()
489
490 # Try valid offset, hopefully 8192 works on all OSes
491 f = open(TESTFN, "r+b")
492 m = mmap.mmap(f.fileno(), mapsize - halfsize, offset=halfsize)
493 self.assertEqual(m[0:3], b'foo')
494 f.close()
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000495
496 # Try resizing map
497 try:
498 m.resize(512)
499 except SystemError:
500 pass
501 else:
502 # resize() is supported
503 self.assertEqual(len(m), 512)
504 # Check that we can no longer seek beyond the new size.
505 self.assertRaises(ValueError, m.seek, 513, 0)
506 # Check that the content is not changed
507 self.assertEqual(m[0:3], b'foo')
508
509 # Check that the underlying file is truncated too
510 f = open(TESTFN)
511 f.seek(0, 2)
512 self.assertEqual(f.tell(), halfsize + 512)
513 f.close()
514 self.assertEqual(m.size(), halfsize + 512)
515
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000516 m.close()
517
518 finally:
519 f.close()
520 try:
521 os.unlink(TESTFN)
522 except OSError:
523 pass
524
Christian Heimes1af737c2008-01-23 08:24:23 +0000525 def test_subclass(self):
526 class anon_mmap(mmap.mmap):
527 def __new__(klass, *args, **kwargs):
528 return mmap.mmap.__new__(klass, -1, *args, **kwargs)
529 anon_mmap(PAGESIZE)
530
Christian Heimesa156e092008-02-16 07:38:31 +0000531 def test_prot_readonly(self):
Christian Heimes18c66892008-02-17 13:31:39 +0000532 if not hasattr(mmap, 'PROT_READ'):
533 return
Christian Heimesa156e092008-02-16 07:38:31 +0000534 mapsize = 10
535 open(TESTFN, "wb").write(b"a"*mapsize)
536 f = open(TESTFN, "rb")
537 m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ)
538 self.assertRaises(TypeError, m.write, "foo")
Martin v. Löwise1e9f232008-04-01 06:17:46 +0000539 f.close()
Christian Heimes1af737c2008-01-23 08:24:23 +0000540
Christian Heimes7131fd92008-02-19 14:21:46 +0000541 def test_error(self):
Georg Brandlab91fde2009-08-13 08:51:18 +0000542 self.assertTrue(issubclass(mmap.error, EnvironmentError))
543 self.assertTrue("mmap.error" in str(mmap.error))
Christian Heimes7131fd92008-02-19 14:21:46 +0000544
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000545 def test_io_methods(self):
546 data = b"0123456789"
547 open(TESTFN, "wb").write(b"x"*len(data))
548 f = open(TESTFN, "r+b")
549 m = mmap.mmap(f.fileno(), len(data))
550 f.close()
551 # Test write_byte()
552 for i in range(len(data)):
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000553 self.assertEqual(m.tell(), i)
Benjamin Petersone099b372009-04-04 17:09:35 +0000554 m.write_byte(data[i])
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000555 self.assertEqual(m.tell(), i+1)
Benjamin Petersone099b372009-04-04 17:09:35 +0000556 self.assertRaises(ValueError, m.write_byte, b"x"[0])
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000557 self.assertEqual(m[:], data)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000558 # Test read_byte()
559 m.seek(0)
560 for i in range(len(data)):
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000561 self.assertEqual(m.tell(), i)
562 self.assertEqual(m.read_byte(), data[i])
563 self.assertEqual(m.tell(), i+1)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000564 self.assertRaises(ValueError, m.read_byte)
565 # Test read()
566 m.seek(3)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000567 self.assertEqual(m.read(3), b"345")
568 self.assertEqual(m.tell(), 6)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000569 # Test write()
570 m.seek(3)
571 m.write(b"bar")
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000572 self.assertEqual(m.tell(), 6)
573 self.assertEqual(m[:], b"012bar6789")
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000574 m.seek(8)
575 self.assertRaises(ValueError, m.write, b"bar")
576
Hirokazu Yamamoto09ea7922010-11-04 12:35:21 +0000577 def test_non_ascii_byte(self):
578 for b in (129, 200, 255): # > 128
579 m = mmap.mmap(-1, 1)
580 m.write_byte(b)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000581 self.assertEqual(m[0], b)
Hirokazu Yamamoto09ea7922010-11-04 12:35:21 +0000582 m.seek(0)
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000583 self.assertEqual(m.read_byte(), b)
Hirokazu Yamamoto09ea7922010-11-04 12:35:21 +0000584 m.close()
585
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000586 if os.name == 'nt':
587 def test_tagname(self):
588 data1 = b"0123456789"
589 data2 = b"abcdefghij"
590 assert len(data1) == len(data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000591
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000592 # Test same tag
593 m1 = mmap.mmap(-1, len(data1), tagname="foo")
594 m1[:] = data1
595 m2 = mmap.mmap(-1, len(data2), tagname="foo")
596 m2[:] = data2
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000597 self.assertEqual(m1[:], data2)
598 self.assertEqual(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000599 m2.close()
600 m1.close()
601
Ezio Melotti13925002011-03-16 11:05:33 +0200602 # Test different tag
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000603 m1 = mmap.mmap(-1, len(data1), tagname="foo")
604 m1[:] = data1
605 m2 = mmap.mmap(-1, len(data2), tagname="boo")
606 m2[:] = data2
Ezio Melotti19f2aeb2010-11-21 01:30:29 +0000607 self.assertEqual(m1[:], data1)
608 self.assertEqual(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000609 m2.close()
610 m1.close()
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000611
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000612 def test_crasher_on_windows(self):
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000613 # Should not crash (Issue 1733986)
614 m = mmap.mmap(-1, 1000, tagname="foo")
615 try:
616 mmap.mmap(-1, 5000, tagname="foo")[:] # same tagname, but larger size
617 except:
618 pass
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000619 m.close()
620
621 # Should not crash (Issue 5385)
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000622 open(TESTFN, "wb").write(b"x"*10)
623 f = open(TESTFN, "r+b")
624 m = mmap.mmap(f.fileno(), 0)
625 f.close()
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000626 try:
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000627 m.resize(0) # will raise WindowsError
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000628 except:
629 pass
630 try:
631 m[:]
632 except:
633 pass
634 m.close()
635
Brian Curtin686ee4f2010-08-01 15:44:11 +0000636 def test_invalid_descriptor(self):
637 # socket file descriptors are valid, but out of range
638 # for _get_osfhandle, causing a crash when validating the
639 # parameters to _get_osfhandle.
640 s = socket.socket()
641 try:
642 with self.assertRaises(mmap.error):
643 m = mmap.mmap(s.fileno(), 10)
644 finally:
645 s.close()
Christian Heimes7131fd92008-02-19 14:21:46 +0000646
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000647
648class LargeMmapTests(unittest.TestCase):
649
650 def setUp(self):
651 unlink(TESTFN)
652
653 def tearDown(self):
654 unlink(TESTFN)
655
656 def _working_largefile(self):
657 # Only run if the current filesystem supports large files.
658 f = open(TESTFN, 'wb', buffering=0)
659 try:
660 f.seek(0x80000001)
661 f.write(b'x')
662 f.flush()
663 except (IOError, OverflowError):
664 raise unittest.SkipTest("filesystem does not have largefile support")
665 finally:
666 f.close()
667 unlink(TESTFN)
668
669 def test_large_offset(self):
670 if sys.platform[:3] == 'win' or sys.platform == 'darwin':
671 requires('largefile',
672 'test requires %s bytes and a long time to run' % str(0x180000000))
673 self._working_largefile()
674 with open(TESTFN, 'wb') as f:
675 f.seek(0x14FFFFFFF)
676 f.write(b" ")
677
678 with open(TESTFN, 'rb') as f:
679 m = mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ)
680 try:
681 self.assertEqual(m[0xFFFFFFF], 32)
682 finally:
683 m.close()
684
685 def test_large_filesize(self):
686 if sys.platform[:3] == 'win' or sys.platform == 'darwin':
687 requires('largefile',
688 'test requires %s bytes and a long time to run' % str(0x180000000))
689 self._working_largefile()
690 with open(TESTFN, 'wb') as f:
691 f.seek(0x17FFFFFFF)
692 f.write(b" ")
693
694 with open(TESTFN, 'rb') as f:
695 m = mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ)
696 try:
697 self.assertEqual(m.size(), 0x180000000)
698 finally:
699 m.close()
700
701
Thomas Wouters89f507f2006-12-13 04:49:30 +0000702def test_main():
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000703 run_unittest(MmapTests, LargeMmapTests)
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +0000704
Thomas Wouters89f507f2006-12-13 04:49:30 +0000705if __name__ == '__main__':
706 test_main()