blob: 5906c02ea96da14485d0903186d55a6a2dde111d [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
Brian Curtinea47eaa2010-08-01 15:26:26 +00003import os, re, itertools, socket
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
Thomas Wouters89f507f2006-12-13 04:49:30 +0000240 def test_bad_file_desc(self):
241 # Try opening a bad file descriptor...
242 self.assertRaises(mmap.error, mmap.mmap, -2, 4096)
Neal Norwitz3b4fff82006-01-11 08:54:45 +0000243
Thomas Wouters89f507f2006-12-13 04:49:30 +0000244 def test_tougher_find(self):
245 # Do a tougher .find() test. SF bug 515943 pointed out that, in 2.2,
246 # searching for data with embedded \0 bytes didn't work.
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000247 f = open(TESTFN, 'wb+')
Tim Petersc9ffa062002-03-08 05:43:32 +0000248
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000249 data = b'aabaac\x00deef\x00\x00aa\x00'
Tim Petersc9ffa062002-03-08 05:43:32 +0000250 n = len(data)
251 f.write(data)
Tim Peters5379dea2002-04-18 04:30:18 +0000252 f.flush()
Tim Petersc9ffa062002-03-08 05:43:32 +0000253 m = mmap.mmap(f.fileno(), n)
254 f.close()
255
256 for start in range(n+1):
257 for finish in range(start, n+1):
258 slice = data[start : finish]
Thomas Wouters89f507f2006-12-13 04:49:30 +0000259 self.assertEqual(m.find(slice), data.find(slice))
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000260 self.assertEqual(m.find(slice + b'x'), -1)
Tim Petersddc82ea2003-01-13 21:38:45 +0000261 m.close()
Tim Petersc9ffa062002-03-08 05:43:32 +0000262
Georg Brandlfceab5a2008-01-19 20:08:23 +0000263 def test_find_end(self):
264 # test the new 'end' parameter works as expected
Benjamin Petersone099b372009-04-04 17:09:35 +0000265 f = open(TESTFN, 'wb+')
266 data = b'one two ones'
Georg Brandlfceab5a2008-01-19 20:08:23 +0000267 n = len(data)
268 f.write(data)
269 f.flush()
270 m = mmap.mmap(f.fileno(), n)
271 f.close()
272
Benjamin Petersone099b372009-04-04 17:09:35 +0000273 self.assertEqual(m.find(b'one'), 0)
274 self.assertEqual(m.find(b'ones'), 8)
275 self.assertEqual(m.find(b'one', 0, -1), 0)
276 self.assertEqual(m.find(b'one', 1), 8)
277 self.assertEqual(m.find(b'one', 1, -1), 8)
278 self.assertEqual(m.find(b'one', 1, -2), -1)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000279
280
281 def test_rfind(self):
282 # test the new 'end' parameter works as expected
Benjamin Petersone099b372009-04-04 17:09:35 +0000283 f = open(TESTFN, 'wb+')
284 data = b'one two ones'
Georg Brandlfceab5a2008-01-19 20:08:23 +0000285 n = len(data)
286 f.write(data)
287 f.flush()
288 m = mmap.mmap(f.fileno(), n)
289 f.close()
290
Benjamin Petersone099b372009-04-04 17:09:35 +0000291 self.assertEqual(m.rfind(b'one'), 8)
292 self.assertEqual(m.rfind(b'one '), 0)
293 self.assertEqual(m.rfind(b'one', 0, -1), 8)
294 self.assertEqual(m.rfind(b'one', 0, -2), 0)
295 self.assertEqual(m.rfind(b'one', 1, -1), 8)
296 self.assertEqual(m.rfind(b'one', 1, -2), -1)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000297
298
Thomas Wouters89f507f2006-12-13 04:49:30 +0000299 def test_double_close(self):
300 # make sure a double close doesn't crash on Solaris (Bug# 665913)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000301 f = open(TESTFN, 'wb+')
Tim Petersc9ffa062002-03-08 05:43:32 +0000302
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000303 f.write(2**16 * b'a') # Arbitrary character
Neal Norwitze604c022003-01-10 20:52:16 +0000304 f.close()
305
306 f = open(TESTFN)
Tim Petersddc82ea2003-01-13 21:38:45 +0000307 mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ)
Neal Norwitze604c022003-01-10 20:52:16 +0000308 mf.close()
309 mf.close()
310 f.close()
311
Thomas Wouters89f507f2006-12-13 04:49:30 +0000312 def test_entire_file(self):
313 # test mapping of entire file by passing 0 for map length
314 if hasattr(os, "stat"):
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000315 f = open(TESTFN, "wb+")
Tim Petersc9ffa062002-03-08 05:43:32 +0000316
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000317 f.write(2**16 * b'm') # Arbitrary character
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000318 f.close()
319
320 f = open(TESTFN, "rb+")
Tim Peterseba28be2005-03-28 01:08:02 +0000321 mf = mmap.mmap(f.fileno(), 0)
Thomas Wouters89f507f2006-12-13 04:49:30 +0000322 self.assertEqual(len(mf), 2**16, "Map size should equal file size.")
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000323 self.assertEqual(mf.read(2**16), 2**16 * b"m")
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000324 mf.close()
325 f.close()
326
Thomas Wouters89f507f2006-12-13 04:49:30 +0000327 def test_move(self):
328 # make move works everywhere (64-bit format problem earlier)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000329 f = open(TESTFN, 'wb+')
Tim Peterseba28be2005-03-28 01:08:02 +0000330
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000331 f.write(b"ABCDEabcde") # Arbitrary character
Neal Norwitz8856fb72005-12-18 03:34:22 +0000332 f.flush()
333
334 mf = mmap.mmap(f.fileno(), 10)
335 mf.move(5, 0, 5)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000336 self.assertEqual(mf[:], b"ABCDEABCDE", "Map move should have duplicated front 5")
Neal Norwitz8856fb72005-12-18 03:34:22 +0000337 mf.close()
338 f.close()
339
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000340 # more excessive test
341 data = b"0123456789"
342 for dest in range(len(data)):
343 for src in range(len(data)):
344 for count in range(len(data) - max(dest, src)):
345 expected = data[:dest] + data[src:src+count] + data[dest+count:]
346 m = mmap.mmap(-1, len(data))
347 m[:] = data
348 m.move(dest, src, count)
349 self.assertEqual(m[:], expected)
350 m.close()
351
Hirokazu Yamamoto2ca15012009-03-31 20:43:56 +0000352 # segfault test (Issue 5387)
353 m = mmap.mmap(-1, 100)
354 offsets = [-100, -1, 0, 1, 100]
355 for source, dest, size in itertools.product(offsets, offsets, offsets):
356 try:
357 m.move(source, dest, size)
358 except ValueError:
359 pass
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000360
361 offsets = [(-1, -1, -1), (-1, -1, 0), (-1, 0, -1), (0, -1, -1),
362 (-1, 0, 0), (0, -1, 0), (0, 0, -1)]
363 for source, dest, size in offsets:
364 self.assertRaises(ValueError, m.move, source, dest, size)
365
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000366 m.close()
367
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000368 m = mmap.mmap(-1, 1) # single byte
369 self.assertRaises(ValueError, m.move, 0, 0, 2)
370 self.assertRaises(ValueError, m.move, 1, 0, 1)
371 self.assertRaises(ValueError, m.move, 0, 1, 1)
372 m.move(0, 0, 1)
373 m.move(0, 0, 0)
374
375
Thomas Wouters89f507f2006-12-13 04:49:30 +0000376 def test_anonymous(self):
377 # anonymous mmap.mmap(-1, PAGE)
378 m = mmap.mmap(-1, PAGESIZE)
Guido van Rossum805365e2007-05-07 22:24:25 +0000379 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000380 self.assertEqual(m[x], 0,
381 "anonymously mmap'ed contents should be zero")
Neal Norwitz8856fb72005-12-18 03:34:22 +0000382
Guido van Rossum805365e2007-05-07 22:24:25 +0000383 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000384 b = x & 0xff
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000385 m[x] = b
386 self.assertEqual(m[x], b)
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000387
Thomas Woutersed03b412007-08-28 21:37:11 +0000388 def test_extended_getslice(self):
389 # Test extended slicing by comparing with list slicing.
390 s = bytes(reversed(range(256)))
391 m = mmap.mmap(-1, len(s))
392 m[:] = s
393 self.assertEqual(m[:], s)
394 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
395 for start in indices:
396 for stop in indices:
397 # Skip step 0 (invalid)
398 for step in indices[1:]:
399 self.assertEqual(m[start:stop:step],
400 s[start:stop:step])
401
402 def test_extended_set_del_slice(self):
403 # Test extended slicing by comparing with list slicing.
404 s = bytes(reversed(range(256)))
405 m = mmap.mmap(-1, len(s))
406 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
407 for start in indices:
408 for stop in indices:
409 # Skip invalid step 0
410 for step in indices[1:]:
411 m[:] = s
412 self.assertEqual(m[:], s)
413 L = list(s)
414 # Make sure we have a slice of exactly the right length,
415 # but with different data.
416 data = L[start:stop:step]
417 data = bytes(reversed(data))
418 L[start:stop:step] = data
419 m[start:stop:step] = data
420 self.assertEquals(m[:], bytes(L))
421
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000422 def make_mmap_file (self, f, halfsize):
423 # Write 2 pages worth of data to the file
424 f.write (b'\0' * halfsize)
425 f.write (b'foo')
426 f.write (b'\0' * (halfsize - 3))
427 f.flush ()
428 return mmap.mmap (f.fileno(), 0)
429
430 def test_offset (self):
431 f = open (TESTFN, 'w+b')
432
433 try: # unlink TESTFN no matter what
434 halfsize = mmap.ALLOCATIONGRANULARITY
435 m = self.make_mmap_file (f, halfsize)
436 m.close ()
437 f.close ()
438
439 mapsize = halfsize * 2
440 # Try invalid offset
441 f = open(TESTFN, "r+b")
442 for offset in [-2, -1, None]:
443 try:
444 m = mmap.mmap(f.fileno(), mapsize, offset=offset)
445 self.assertEqual(0, 1)
446 except (ValueError, TypeError, OverflowError):
447 pass
448 else:
449 self.assertEqual(0, 0)
450 f.close()
451
452 # Try valid offset, hopefully 8192 works on all OSes
453 f = open(TESTFN, "r+b")
454 m = mmap.mmap(f.fileno(), mapsize - halfsize, offset=halfsize)
455 self.assertEqual(m[0:3], b'foo')
456 f.close()
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000457
458 # Try resizing map
459 try:
460 m.resize(512)
461 except SystemError:
462 pass
463 else:
464 # resize() is supported
465 self.assertEqual(len(m), 512)
466 # Check that we can no longer seek beyond the new size.
467 self.assertRaises(ValueError, m.seek, 513, 0)
468 # Check that the content is not changed
469 self.assertEqual(m[0:3], b'foo')
470
471 # Check that the underlying file is truncated too
472 f = open(TESTFN)
473 f.seek(0, 2)
474 self.assertEqual(f.tell(), halfsize + 512)
475 f.close()
476 self.assertEqual(m.size(), halfsize + 512)
477
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000478 m.close()
479
480 finally:
481 f.close()
482 try:
483 os.unlink(TESTFN)
484 except OSError:
485 pass
486
Christian Heimes1af737c2008-01-23 08:24:23 +0000487 def test_subclass(self):
488 class anon_mmap(mmap.mmap):
489 def __new__(klass, *args, **kwargs):
490 return mmap.mmap.__new__(klass, -1, *args, **kwargs)
491 anon_mmap(PAGESIZE)
492
Christian Heimesa156e092008-02-16 07:38:31 +0000493 def test_prot_readonly(self):
Christian Heimes18c66892008-02-17 13:31:39 +0000494 if not hasattr(mmap, 'PROT_READ'):
495 return
Christian Heimesa156e092008-02-16 07:38:31 +0000496 mapsize = 10
497 open(TESTFN, "wb").write(b"a"*mapsize)
498 f = open(TESTFN, "rb")
499 m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ)
500 self.assertRaises(TypeError, m.write, "foo")
Martin v. Löwise1e9f232008-04-01 06:17:46 +0000501 f.close()
Christian Heimes1af737c2008-01-23 08:24:23 +0000502
Christian Heimes7131fd92008-02-19 14:21:46 +0000503 def test_error(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000504 self.assertTrue(issubclass(mmap.error, EnvironmentError))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000505 self.assertIn("mmap.error", str(mmap.error))
Christian Heimes7131fd92008-02-19 14:21:46 +0000506
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000507 def test_io_methods(self):
508 data = b"0123456789"
509 open(TESTFN, "wb").write(b"x"*len(data))
510 f = open(TESTFN, "r+b")
511 m = mmap.mmap(f.fileno(), len(data))
512 f.close()
513 # Test write_byte()
514 for i in range(len(data)):
515 self.assertEquals(m.tell(), i)
Benjamin Petersone099b372009-04-04 17:09:35 +0000516 m.write_byte(data[i])
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000517 self.assertEquals(m.tell(), i+1)
Benjamin Petersone099b372009-04-04 17:09:35 +0000518 self.assertRaises(ValueError, m.write_byte, b"x"[0])
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000519 self.assertEquals(m[:], data)
520 # Test read_byte()
521 m.seek(0)
522 for i in range(len(data)):
523 self.assertEquals(m.tell(), i)
Benjamin Petersone099b372009-04-04 17:09:35 +0000524 self.assertEquals(m.read_byte(), data[i])
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000525 self.assertEquals(m.tell(), i+1)
526 self.assertRaises(ValueError, m.read_byte)
527 # Test read()
528 m.seek(3)
529 self.assertEquals(m.read(3), b"345")
530 self.assertEquals(m.tell(), 6)
531 # Test write()
532 m.seek(3)
533 m.write(b"bar")
534 self.assertEquals(m.tell(), 6)
535 self.assertEquals(m[:], b"012bar6789")
536 m.seek(8)
537 self.assertRaises(ValueError, m.write, b"bar")
538
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000539 if os.name == 'nt':
540 def test_tagname(self):
541 data1 = b"0123456789"
542 data2 = b"abcdefghij"
543 assert len(data1) == len(data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000544
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000545 # Test same tag
546 m1 = mmap.mmap(-1, len(data1), tagname="foo")
547 m1[:] = data1
548 m2 = mmap.mmap(-1, len(data2), tagname="foo")
549 m2[:] = data2
550 self.assertEquals(m1[:], data2)
551 self.assertEquals(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000552 m2.close()
553 m1.close()
554
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000555 # Test differnt tag
556 m1 = mmap.mmap(-1, len(data1), tagname="foo")
557 m1[:] = data1
558 m2 = mmap.mmap(-1, len(data2), tagname="boo")
559 m2[:] = data2
560 self.assertEquals(m1[:], data1)
561 self.assertEquals(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000562 m2.close()
563 m1.close()
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000564
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000565 def test_crasher_on_windows(self):
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000566 # Should not crash (Issue 1733986)
567 m = mmap.mmap(-1, 1000, tagname="foo")
568 try:
569 mmap.mmap(-1, 5000, tagname="foo")[:] # same tagname, but larger size
570 except:
571 pass
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000572 m.close()
573
574 # Should not crash (Issue 5385)
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000575 open(TESTFN, "wb").write(b"x"*10)
576 f = open(TESTFN, "r+b")
577 m = mmap.mmap(f.fileno(), 0)
578 f.close()
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000579 try:
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000580 m.resize(0) # will raise WindowsError
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000581 except:
582 pass
583 try:
584 m[:]
585 except:
586 pass
587 m.close()
588
Brian Curtinea47eaa2010-08-01 15:26:26 +0000589 def test_invalid_descriptor(self):
590 # socket file descriptors are valid, but out of range
591 # for _get_osfhandle, causing a crash when validating the
592 # parameters to _get_osfhandle.
593 s = socket.socket()
594 try:
595 with self.assertRaises(mmap.error):
596 m = mmap.mmap(s.fileno(), 10)
597 finally:
598 s.close()
599
Georg Brandl0bccc182010-08-01 14:50:00 +0000600 def test_context_manager(self):
601 with mmap.mmap(-1, 10) as m:
602 self.assertFalse(m.closed)
603 self.assertTrue(m.closed)
604
605 def test_context_manager_exception(self):
606 # Test that the IOError gets passed through
607 with self.assertRaises(Exception) as exc:
608 with mmap.mmap(-1, 10) as m:
609 raise IOError
610 self.assertIsInstance(exc.exception, IOError,
611 "wrong exception raised in context manager")
612 self.assertTrue(m.closed, "context manager failed")
613
Christian Heimes7131fd92008-02-19 14:21:46 +0000614
Thomas Wouters89f507f2006-12-13 04:49:30 +0000615def test_main():
616 run_unittest(MmapTests)
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +0000617
Thomas Wouters89f507f2006-12-13 04:49:30 +0000618if __name__ == '__main__':
619 test_main()