blob: abfde01ae49bb1f9a1d6415c7a6c9e10aa463a5c [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
Thomas Wouters89f507f2006-12-13 04:49:30 +0000323 def test_move(self):
324 # make move works everywhere (64-bit format problem earlier)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000325 f = open(TESTFN, 'wb+')
Tim Peterseba28be2005-03-28 01:08:02 +0000326
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000327 f.write(b"ABCDEabcde") # Arbitrary character
Neal Norwitz8856fb72005-12-18 03:34:22 +0000328 f.flush()
329
330 mf = mmap.mmap(f.fileno(), 10)
331 mf.move(5, 0, 5)
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000332 self.assertEqual(mf[:], b"ABCDEABCDE", "Map move should have duplicated front 5")
Neal Norwitz8856fb72005-12-18 03:34:22 +0000333 mf.close()
334 f.close()
335
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000336 # more excessive test
337 data = b"0123456789"
338 for dest in range(len(data)):
339 for src in range(len(data)):
340 for count in range(len(data) - max(dest, src)):
341 expected = data[:dest] + data[src:src+count] + data[dest+count:]
342 m = mmap.mmap(-1, len(data))
343 m[:] = data
344 m.move(dest, src, count)
345 self.assertEqual(m[:], expected)
346 m.close()
347
Hirokazu Yamamoto2ca15012009-03-31 20:43:56 +0000348 # segfault test (Issue 5387)
349 m = mmap.mmap(-1, 100)
350 offsets = [-100, -1, 0, 1, 100]
351 for source, dest, size in itertools.product(offsets, offsets, offsets):
352 try:
353 m.move(source, dest, size)
354 except ValueError:
355 pass
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000356
357 offsets = [(-1, -1, -1), (-1, -1, 0), (-1, 0, -1), (0, -1, -1),
358 (-1, 0, 0), (0, -1, 0), (0, 0, -1)]
359 for source, dest, size in offsets:
360 self.assertRaises(ValueError, m.move, source, dest, size)
361
Hirokazu Yamamoto16caab02009-03-31 13:44:06 +0000362 m.close()
363
Benjamin Petersonef3e4c22009-04-11 19:48:14 +0000364 m = mmap.mmap(-1, 1) # single byte
365 self.assertRaises(ValueError, m.move, 0, 0, 2)
366 self.assertRaises(ValueError, m.move, 1, 0, 1)
367 self.assertRaises(ValueError, m.move, 0, 1, 1)
368 m.move(0, 0, 1)
369 m.move(0, 0, 0)
370
371
Thomas Wouters89f507f2006-12-13 04:49:30 +0000372 def test_anonymous(self):
373 # anonymous mmap.mmap(-1, PAGE)
374 m = mmap.mmap(-1, PAGESIZE)
Guido van Rossum805365e2007-05-07 22:24:25 +0000375 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000376 self.assertEqual(m[x], 0,
377 "anonymously mmap'ed contents should be zero")
Neal Norwitz8856fb72005-12-18 03:34:22 +0000378
Guido van Rossum805365e2007-05-07 22:24:25 +0000379 for x in range(PAGESIZE):
Guido van Rossum98297ee2007-11-06 21:34:58 +0000380 b = x & 0xff
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000381 m[x] = b
382 self.assertEqual(m[x], b)
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000383
Thomas Woutersed03b412007-08-28 21:37:11 +0000384 def test_extended_getslice(self):
385 # Test extended slicing by comparing with list slicing.
386 s = bytes(reversed(range(256)))
387 m = mmap.mmap(-1, len(s))
388 m[:] = s
389 self.assertEqual(m[:], s)
390 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
391 for start in indices:
392 for stop in indices:
393 # Skip step 0 (invalid)
394 for step in indices[1:]:
395 self.assertEqual(m[start:stop:step],
396 s[start:stop:step])
397
398 def test_extended_set_del_slice(self):
399 # Test extended slicing by comparing with list slicing.
400 s = bytes(reversed(range(256)))
401 m = mmap.mmap(-1, len(s))
402 indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
403 for start in indices:
404 for stop in indices:
405 # Skip invalid step 0
406 for step in indices[1:]:
407 m[:] = s
408 self.assertEqual(m[:], s)
409 L = list(s)
410 # Make sure we have a slice of exactly the right length,
411 # but with different data.
412 data = L[start:stop:step]
413 data = bytes(reversed(data))
414 L[start:stop:step] = data
415 m[start:stop:step] = data
Ezio Melottib3aedd42010-11-20 19:04:17 +0000416 self.assertEqual(m[:], bytes(L))
Thomas Woutersed03b412007-08-28 21:37:11 +0000417
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000418 def make_mmap_file (self, f, halfsize):
419 # Write 2 pages worth of data to the file
420 f.write (b'\0' * halfsize)
421 f.write (b'foo')
422 f.write (b'\0' * (halfsize - 3))
423 f.flush ()
424 return mmap.mmap (f.fileno(), 0)
425
426 def test_offset (self):
427 f = open (TESTFN, 'w+b')
428
429 try: # unlink TESTFN no matter what
430 halfsize = mmap.ALLOCATIONGRANULARITY
431 m = self.make_mmap_file (f, halfsize)
432 m.close ()
433 f.close ()
434
435 mapsize = halfsize * 2
436 # Try invalid offset
437 f = open(TESTFN, "r+b")
438 for offset in [-2, -1, None]:
439 try:
440 m = mmap.mmap(f.fileno(), mapsize, offset=offset)
441 self.assertEqual(0, 1)
442 except (ValueError, TypeError, OverflowError):
443 pass
444 else:
445 self.assertEqual(0, 0)
446 f.close()
447
448 # Try valid offset, hopefully 8192 works on all OSes
449 f = open(TESTFN, "r+b")
450 m = mmap.mmap(f.fileno(), mapsize - halfsize, offset=halfsize)
451 self.assertEqual(m[0:3], b'foo')
452 f.close()
Hirokazu Yamamoto0654ccd2009-02-18 16:38:00 +0000453
454 # Try resizing map
455 try:
456 m.resize(512)
457 except SystemError:
458 pass
459 else:
460 # resize() is supported
461 self.assertEqual(len(m), 512)
462 # Check that we can no longer seek beyond the new size.
463 self.assertRaises(ValueError, m.seek, 513, 0)
464 # Check that the content is not changed
465 self.assertEqual(m[0:3], b'foo')
466
467 # Check that the underlying file is truncated too
468 f = open(TESTFN)
469 f.seek(0, 2)
470 self.assertEqual(f.tell(), halfsize + 512)
471 f.close()
472 self.assertEqual(m.size(), halfsize + 512)
473
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000474 m.close()
475
476 finally:
477 f.close()
478 try:
479 os.unlink(TESTFN)
480 except OSError:
481 pass
482
Christian Heimes1af737c2008-01-23 08:24:23 +0000483 def test_subclass(self):
484 class anon_mmap(mmap.mmap):
485 def __new__(klass, *args, **kwargs):
486 return mmap.mmap.__new__(klass, -1, *args, **kwargs)
487 anon_mmap(PAGESIZE)
488
Christian Heimesa156e092008-02-16 07:38:31 +0000489 def test_prot_readonly(self):
Christian Heimes18c66892008-02-17 13:31:39 +0000490 if not hasattr(mmap, 'PROT_READ'):
491 return
Christian Heimesa156e092008-02-16 07:38:31 +0000492 mapsize = 10
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000493 with open(TESTFN, "wb") as fp:
494 fp.write(b"a"*mapsize)
Christian Heimesa156e092008-02-16 07:38:31 +0000495 f = open(TESTFN, "rb")
496 m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ)
497 self.assertRaises(TypeError, m.write, "foo")
Martin v. Löwise1e9f232008-04-01 06:17:46 +0000498 f.close()
Christian Heimes1af737c2008-01-23 08:24:23 +0000499
Christian Heimes7131fd92008-02-19 14:21:46 +0000500 def test_error(self):
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000501 self.assertTrue(issubclass(mmap.error, EnvironmentError))
Benjamin Peterson577473f2010-01-19 00:09:57 +0000502 self.assertIn("mmap.error", str(mmap.error))
Christian Heimes7131fd92008-02-19 14:21:46 +0000503
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000504 def test_io_methods(self):
505 data = b"0123456789"
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000506 with open(TESTFN, "wb") as fp:
507 fp.write(b"x"*len(data))
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000508 f = open(TESTFN, "r+b")
509 m = mmap.mmap(f.fileno(), len(data))
510 f.close()
511 # Test write_byte()
512 for i in range(len(data)):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000513 self.assertEqual(m.tell(), i)
Benjamin Petersone099b372009-04-04 17:09:35 +0000514 m.write_byte(data[i])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000515 self.assertEqual(m.tell(), i+1)
Benjamin Petersone099b372009-04-04 17:09:35 +0000516 self.assertRaises(ValueError, m.write_byte, b"x"[0])
Ezio Melottib3aedd42010-11-20 19:04:17 +0000517 self.assertEqual(m[:], data)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000518 # Test read_byte()
519 m.seek(0)
520 for i in range(len(data)):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000521 self.assertEqual(m.tell(), i)
522 self.assertEqual(m.read_byte(), data[i])
523 self.assertEqual(m.tell(), i+1)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000524 self.assertRaises(ValueError, m.read_byte)
525 # Test read()
526 m.seek(3)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000527 self.assertEqual(m.read(3), b"345")
528 self.assertEqual(m.tell(), 6)
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000529 # Test write()
530 m.seek(3)
531 m.write(b"bar")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000532 self.assertEqual(m.tell(), 6)
533 self.assertEqual(m[:], b"012bar6789")
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000534 m.seek(8)
535 self.assertRaises(ValueError, m.write, b"bar")
536
Hirokazu Yamamoto3cdd5cb2010-11-04 12:09:08 +0000537 def test_non_ascii_byte(self):
538 for b in (129, 200, 255): # > 128
539 m = mmap.mmap(-1, 1)
540 m.write_byte(b)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000541 self.assertEqual(m[0], b)
Hirokazu Yamamoto3cdd5cb2010-11-04 12:09:08 +0000542 m.seek(0)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000543 self.assertEqual(m.read_byte(), b)
Hirokazu Yamamoto3cdd5cb2010-11-04 12:09:08 +0000544 m.close()
545
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000546 if os.name == 'nt':
547 def test_tagname(self):
548 data1 = b"0123456789"
549 data2 = b"abcdefghij"
550 assert len(data1) == len(data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000551
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000552 # Test same tag
553 m1 = mmap.mmap(-1, len(data1), tagname="foo")
554 m1[:] = data1
555 m2 = mmap.mmap(-1, len(data2), tagname="foo")
556 m2[:] = data2
Ezio Melottib3aedd42010-11-20 19:04:17 +0000557 self.assertEqual(m1[:], data2)
558 self.assertEqual(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000559 m2.close()
560 m1.close()
561
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000562 # Test differnt tag
563 m1 = mmap.mmap(-1, len(data1), tagname="foo")
564 m1[:] = data1
565 m2 = mmap.mmap(-1, len(data2), tagname="boo")
566 m2[:] = data2
Ezio Melottib3aedd42010-11-20 19:04:17 +0000567 self.assertEqual(m1[:], data1)
568 self.assertEqual(m2[:], data2)
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000569 m2.close()
570 m1.close()
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000571
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000572 def test_crasher_on_windows(self):
Hirokazu Yamamoto10c99372009-02-28 12:21:53 +0000573 # Should not crash (Issue 1733986)
574 m = mmap.mmap(-1, 1000, tagname="foo")
575 try:
576 mmap.mmap(-1, 5000, tagname="foo")[:] # same tagname, but larger size
577 except:
578 pass
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000579 m.close()
580
581 # Should not crash (Issue 5385)
Benjamin Peterson5dc8fab2010-10-31 01:44:49 +0000582 with open(TESTFN, "wb") as fp:
583 fp.write(b"x"*10)
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000584 f = open(TESTFN, "r+b")
585 m = mmap.mmap(f.fileno(), 0)
586 f.close()
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000587 try:
Hirokazu Yamamoto9b789252009-03-05 15:00:28 +0000588 m.resize(0) # will raise WindowsError
Hirokazu Yamamoto8e722bc2009-03-05 14:33:01 +0000589 except:
590 pass
591 try:
592 m[:]
593 except:
594 pass
595 m.close()
596
Brian Curtinea47eaa2010-08-01 15:26:26 +0000597 def test_invalid_descriptor(self):
598 # socket file descriptors are valid, but out of range
599 # for _get_osfhandle, causing a crash when validating the
600 # parameters to _get_osfhandle.
601 s = socket.socket()
602 try:
603 with self.assertRaises(mmap.error):
604 m = mmap.mmap(s.fileno(), 10)
605 finally:
606 s.close()
607
Georg Brandl0bccc182010-08-01 14:50:00 +0000608 def test_context_manager(self):
609 with mmap.mmap(-1, 10) as m:
610 self.assertFalse(m.closed)
611 self.assertTrue(m.closed)
612
613 def test_context_manager_exception(self):
614 # Test that the IOError gets passed through
615 with self.assertRaises(Exception) as exc:
616 with mmap.mmap(-1, 10) as m:
617 raise IOError
618 self.assertIsInstance(exc.exception, IOError,
619 "wrong exception raised in context manager")
620 self.assertTrue(m.closed, "context manager failed")
621
Christian Heimes7131fd92008-02-19 14:21:46 +0000622
Thomas Wouters89f507f2006-12-13 04:49:30 +0000623def test_main():
624 run_unittest(MmapTests)
Andrew M. Kuchlinge81b9cf2000-03-30 21:15:29 +0000625
Thomas Wouters89f507f2006-12-13 04:49:30 +0000626if __name__ == '__main__':
627 test_main()