blob: f3e28ccac9e77f1c5bf6eb3a04032a40c911fb63 [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
Hirokazu Yamamoto2ca15012009-03-31 20:43:56 +00003import os, re, itertools
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
360 self.assertRaises(ValueError, m.move, -1, -1, -1)
361 self.assertRaises(ValueError, m.move, -1, -1, 0)
362 self.assertRaises(ValueError, m.move, -1, 0, -1)
363 self.assertRaises(ValueError, m.move, 0, -1, -1)
364 self.assertRaises(ValueError, m.move, -1, 0, 0)
365 self.assertRaises(ValueError, m.move, 0, -1, 0)
366 self.assertRaises(ValueError, m.move, 0, 0, -1)
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000367 m.close()
368
Thomas Wouters89f507f2006-12-13 04:49:30 +0000369 def test_anonymous(self):
370 # anonymous mmap.mmap(-1, PAGE)
371 m = mmap.mmap(-1, PAGESIZE)
Guido van Rossum805365e2007-05-07 22:24:25 +0000372 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000373 self.assertEqual(m[x], 0,
374 "anonymously mmap'ed contents should be zero")
Neal Norwitz8856fb72005-12-18 03:34:22 +0000375
Guido van Rossum805365e2007-05-07 22:24:25 +0000376 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000377 b = x & 0xff
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000378 m[x] = b
379 self.assertEqual(m[x], b)
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000380
Thomas Woutersed03b412007-08-28 21:37:11 +0000381 def test_extended_getslice(self):
382 # Test extended slicing by comparing with list slicing.
383 s = bytes(reversed(range(256)))
384 m = mmap.mmap(-1, len(s))
385 m[:] = s
386 self.assertEqual(m[:], s)
387 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
388 for start in indices:
389 for stop in indices:
390 # Skip step 0 (invalid)
391 for step in indices[1:]:
392 self.assertEqual(m[start:stop:step],
393 s[start:stop:step])
394
395 def test_extended_set_del_slice(self):
396 # Test extended slicing by comparing with list slicing.
397 s = bytes(reversed(range(256)))
398 m = mmap.mmap(-1, len(s))
399 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
400 for start in indices:
401 for stop in indices:
402 # Skip invalid step 0
403 for step in indices[1:]:
404 m[:] = s
405 self.assertEqual(m[:], s)
406 L = list(s)
407 # Make sure we have a slice of exactly the right length,
408 # but with different data.
409 data = L[start:stop:step]
410 data = bytes(reversed(data))
411 L[start:stop:step] = data
412 m[start:stop:step] = data
413 self.assertEquals(m[:], bytes(L))
414
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000415 def make_mmap_file (self, f, halfsize):
416 # Write 2 pages worth of data to the file
417 f.write (b'\0' * halfsize)
418 f.write (b'foo')
419 f.write (b'\0' * (halfsize - 3))
420 f.flush ()
421 return mmap.mmap (f.fileno(), 0)
422
423 def test_offset (self):
424 f = open (TESTFN, 'w+b')
425
426 try: # unlink TESTFN no matter what
427 halfsize = mmap.ALLOCATIONGRANULARITY
428 m = self.make_mmap_file (f, halfsize)
429 m.close ()
430 f.close ()
431
432 mapsize = halfsize * 2
433 # Try invalid offset
434 f = open(TESTFN, "r+b")
435 for offset in [-2, -1, None]:
436 try:
437 m = mmap.mmap(f.fileno(), mapsize, offset=offset)
438 self.assertEqual(0, 1)
439 except (ValueError, TypeError, OverflowError):
440 pass
441 else:
442 self.assertEqual(0, 0)
443 f.close()
444
445 # Try valid offset, hopefully 8192 works on all OSes
446 f = open(TESTFN, "r+b")
447 m = mmap.mmap(f.fileno(), mapsize - halfsize, offset=halfsize)
448 self.assertEqual(m[0:3], b'foo')
449 f.close()
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000450
451 # Try resizing map
452 try:
453 m.resize(512)
454 except SystemError:
455 pass
456 else:
457 # resize() is supported
458 self.assertEqual(len(m), 512)
459 # Check that we can no longer seek beyond the new size.
460 self.assertRaises(ValueError, m.seek, 513, 0)
461 # Check that the content is not changed
462 self.assertEqual(m[0:3], b'foo')
463
464 # Check that the underlying file is truncated too
465 f = open(TESTFN)
466 f.seek(0, 2)
467 self.assertEqual(f.tell(), halfsize + 512)
468 f.close()
469 self.assertEqual(m.size(), halfsize + 512)
470
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000471 m.close()
472
473 finally:
474 f.close()
475 try:
476 os.unlink(TESTFN)
477 except OSError:
478 pass
479
Christian Heimes1af737c2008-01-23 08:24:23 +0000480 def test_subclass(self):
481 class anon_mmap(mmap.mmap):
482 def __new__(klass, *args, **kwargs):
483 return mmap.mmap.__new__(klass, -1, *args, **kwargs)
484 anon_mmap(PAGESIZE)
485
Christian Heimesa156e092008-02-16 07:38:31 +0000486 def test_prot_readonly(self):
Christian Heimes18c66892008-02-17 13:31:39 +0000487 if not hasattr(mmap, 'PROT_READ'):
488 return
Christian Heimesa156e092008-02-16 07:38:31 +0000489 mapsize = 10
490 open(TESTFN, "wb").write(b"a"*mapsize)
491 f = open(TESTFN, "rb")
492 m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ)
493 self.assertRaises(TypeError, m.write, "foo")
Martin v. Löwise1e9f232008-04-01 06:17:46 +0000494 f.close()
Christian Heimes1af737c2008-01-23 08:24:23 +0000495
Christian Heimes7131fd92008-02-19 14:21:46 +0000496 def test_error(self):
497 self.assert_(issubclass(mmap.error, EnvironmentError))
498 self.assert_("mmap.error" in str(mmap.error))
499
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000500 def test_io_methods(self):
501 data = b"0123456789"
502 open(TESTFN, "wb").write(b"x"*len(data))
503 f = open(TESTFN, "r+b")
504 m = mmap.mmap(f.fileno(), len(data))
505 f.close()
506 # Test write_byte()
507 for i in range(len(data)):
508 self.assertEquals(m.tell(), i)
Benjamin Petersone099b372009-04-04 17:09:35 +0000509 m.write_byte(data[i])
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000510 self.assertEquals(m.tell(), i+1)
Benjamin Petersone099b372009-04-04 17:09:35 +0000511 self.assertRaises(ValueError, m.write_byte, b"x"[0])
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000512 self.assertEquals(m[:], data)
513 # Test read_byte()
514 m.seek(0)
515 for i in range(len(data)):
516 self.assertEquals(m.tell(), i)
Benjamin Petersone099b372009-04-04 17:09:35 +0000517 self.assertEquals(m.read_byte(), data[i])
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000518 self.assertEquals(m.tell(), i+1)
519 self.assertRaises(ValueError, m.read_byte)
520 # Test read()
521 m.seek(3)
522 self.assertEquals(m.read(3), b"345")
523 self.assertEquals(m.tell(), 6)
524 # Test write()
525 m.seek(3)
526 m.write(b"bar")
527 self.assertEquals(m.tell(), 6)
528 self.assertEquals(m[:], b"012bar6789")
529 m.seek(8)
530 self.assertRaises(ValueError, m.write, b"bar")
531
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000532 if os.name == 'nt':
533 def test_tagname(self):
534 data1 = b"0123456789"
535 data2 = b"abcdefghij"
536 assert len(data1) == len(data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000537
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000538 # Test same tag
539 m1 = mmap.mmap(-1, len(data1), tagname="foo")
540 m1[:] = data1
541 m2 = mmap.mmap(-1, len(data2), tagname="foo")
542 m2[:] = data2
543 self.assertEquals(m1[:], data2)
544 self.assertEquals(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000545 m2.close()
546 m1.close()
547
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000548 # Test differnt tag
549 m1 = mmap.mmap(-1, len(data1), tagname="foo")
550 m1[:] = data1
551 m2 = mmap.mmap(-1, len(data2), tagname="boo")
552 m2[:] = data2
553 self.assertEquals(m1[:], data1)
554 self.assertEquals(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000555 m2.close()
556 m1.close()
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000557
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000558 def test_crasher_on_windows(self):
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000559 # Should not crash (Issue 1733986)
560 m = mmap.mmap(-1, 1000, tagname="foo")
561 try:
562 mmap.mmap(-1, 5000, tagname="foo")[:] # same tagname, but larger size
563 except:
564 pass
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000565 m.close()
566
567 # Should not crash (Issue 5385)
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000568 open(TESTFN, "wb").write(b"x"*10)
569 f = open(TESTFN, "r+b")
570 m = mmap.mmap(f.fileno(), 0)
571 f.close()
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000572 try:
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000573 m.resize(0) # will raise WindowsError
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000574 except:
575 pass
576 try:
577 m[:]
578 except:
579 pass
580 m.close()
581
Christian Heimes7131fd92008-02-19 14:21:46 +0000582
Thomas Wouters89f507f2006-12-13 04:49:30 +0000583def test_main():
584 run_unittest(MmapTests)
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +0000585
Thomas Wouters89f507f2006-12-13 04:49:30 +0000586if __name__ == '__main__':
587 test_main()