Home | History | Annotate | Download | only in test
      1 from test.test_support import (TESTFN, run_unittest, import_module, unlink,
      2                                requires, _2G, _4G, gc_collect, cpython_only)
      3 import unittest
      4 import os, re, itertools, socket, sys
      5 
      6 mmap = import_module('mmap')
      7 
      8 PAGESIZE = mmap.PAGESIZE
      9 
     10 class MmapTests(unittest.TestCase):
     11 
     12     def setUp(self):
     13         if os.path.exists(TESTFN):
     14             os.unlink(TESTFN)
     15 
     16     def tearDown(self):
     17         try:
     18             os.unlink(TESTFN)
     19         except OSError:
     20             pass
     21 
     22     def test_basic(self):
     23         # Test mmap module on Unix systems and Windows
     24 
     25         # Create a file to be mmap'ed.
     26         f = open(TESTFN, 'w+')
     27         try:
     28             # Write 2 pages worth of data to the file
     29             f.write('\0'* PAGESIZE)
     30             f.write('foo')
     31             f.write('\0'* (PAGESIZE-3) )
     32             f.flush()
     33             m = mmap.mmap(f.fileno(), 2 * PAGESIZE)
     34             f.close()
     35 
     36             # Simple sanity checks
     37 
     38             tp = str(type(m))  # SF bug 128713:  segfaulted on Linux
     39             self.assertEqual(m.find('foo'), PAGESIZE)
     40 
     41             self.assertEqual(len(m), 2*PAGESIZE)
     42 
     43             self.assertEqual(m[0], '\0')
     44             self.assertEqual(m[0:3], '\0\0\0')
     45 
     46             # Shouldn't crash on boundary (Issue #5292)
     47             self.assertRaises(IndexError, m.__getitem__, len(m))
     48             self.assertRaises(IndexError, m.__setitem__, len(m), '\0')
     49 
     50             # Modify the file's content
     51             m[0] = '3'
     52             m[PAGESIZE +3: PAGESIZE +3+3] = 'bar'
     53 
     54             # Check that the modification worked
     55             self.assertEqual(m[0], '3')
     56             self.assertEqual(m[0:3], '3\0\0')
     57             self.assertEqual(m[PAGESIZE-1 : PAGESIZE + 7], '\0foobar\0')
     58 
     59             m.flush()
     60 
     61             # Test doing a regular expression match in an mmap'ed file
     62             match = re.search('[A-Za-z]+', m)
     63             if match is None:
     64                 self.fail('regex match on mmap failed!')
     65             else:
     66                 start, end = match.span(0)
     67                 length = end - start
     68 
     69                 self.assertEqual(start, PAGESIZE)
     70                 self.assertEqual(end, PAGESIZE + 6)
     71 
     72             # test seeking around (try to overflow the seek implementation)
     73             m.seek(0,0)
     74             self.assertEqual(m.tell(), 0)
     75             m.seek(42,1)
     76             self.assertEqual(m.tell(), 42)
     77             m.seek(0,2)
     78             self.assertEqual(m.tell(), len(m))
     79 
     80             # Try to seek to negative position...
     81             self.assertRaises(ValueError, m.seek, -1)
     82 
     83             # Try to seek beyond end of mmap...
     84             self.assertRaises(ValueError, m.seek, 1, 2)
     85 
     86             # Try to seek to negative position...
     87             self.assertRaises(ValueError, m.seek, -len(m)-1, 2)
     88 
     89             # Try resizing map
     90             try:
     91                 m.resize(512)
     92             except SystemError:
     93                 # resize() not supported
     94                 # No messages are printed, since the output of this test suite
     95                 # would then be different across platforms.
     96                 pass
     97             else:
     98                 # resize() is supported
     99                 self.assertEqual(len(m), 512)
    100                 # Check that we can no longer seek beyond the new size.
    101                 self.assertRaises(ValueError, m.seek, 513, 0)
    102 
    103                 # Check that the underlying file is truncated too
    104                 # (bug #728515)
    105                 f = open(TESTFN)
    106                 f.seek(0, 2)
    107                 self.assertEqual(f.tell(), 512)
    108                 f.close()
    109                 self.assertEqual(m.size(), 512)
    110 
    111             m.close()
    112 
    113         finally:
    114             try:
    115                 f.close()
    116             except OSError:
    117                 pass
    118 
    119     def test_access_parameter(self):
    120         # Test for "access" keyword parameter
    121         mapsize = 10
    122         open(TESTFN, "wb").write("a"*mapsize)
    123         f = open(TESTFN, "rb")
    124         m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_READ)
    125         self.assertEqual(m[:], 'a'*mapsize, "Readonly memory map data incorrect.")
    126 
    127         # Ensuring that readonly mmap can't be slice assigned
    128         try:
    129             m[:] = 'b'*mapsize
    130         except TypeError:
    131             pass
    132         else:
    133             self.fail("Able to write to readonly memory map")
    134 
    135         # Ensuring that readonly mmap can't be item assigned
    136         try:
    137             m[0] = 'b'
    138         except TypeError:
    139             pass
    140         else:
    141             self.fail("Able to write to readonly memory map")
    142 
    143         # Ensuring that readonly mmap can't be write() to
    144         try:
    145             m.seek(0,0)
    146             m.write('abc')
    147         except TypeError:
    148             pass
    149         else:
    150             self.fail("Able to write to readonly memory map")
    151 
    152         # Ensuring that readonly mmap can't be write_byte() to
    153         try:
    154             m.seek(0,0)
    155             m.write_byte('d')
    156         except TypeError:
    157             pass
    158         else:
    159             self.fail("Able to write to readonly memory map")
    160 
    161         # Ensuring that readonly mmap can't be resized
    162         try:
    163             m.resize(2*mapsize)
    164         except SystemError:   # resize is not universally supported
    165             pass
    166         except TypeError:
    167             pass
    168         else:
    169             self.fail("Able to resize readonly memory map")
    170         f.close()
    171         del m, f
    172         self.assertEqual(open(TESTFN, "rb").read(), 'a'*mapsize,
    173                "Readonly memory map data file was modified")
    174 
    175         # Opening mmap with size too big
    176         import sys
    177         f = open(TESTFN, "r+b")
    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()
    192         f.close()
    193         if sys.platform.startswith('win'):
    194             # Repair damage from the resizing test.
    195             f = open(TESTFN, 'r+b')
    196             f.truncate(mapsize)
    197             f.close()
    198 
    199         # Opening mmap with access=ACCESS_WRITE
    200         f = open(TESTFN, "r+b")
    201         m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_WRITE)
    202         # Modifying write-through memory map
    203         m[:] = 'c'*mapsize
    204         self.assertEqual(m[:], 'c'*mapsize,
    205                "Write-through memory map memory not updated properly.")
    206         m.flush()
    207         m.close()
    208         f.close()
    209         f = open(TESTFN, 'rb')
    210         stuff = f.read()
    211         f.close()
    212         self.assertEqual(stuff, 'c'*mapsize,
    213                "Write-through memory map data file not updated properly.")
    214 
    215         # Opening mmap with access=ACCESS_COPY
    216         f = open(TESTFN, "r+b")
    217         m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_COPY)
    218         # Modifying copy-on-write memory map
    219         m[:] = 'd'*mapsize
    220         self.assertEqual(m[:], 'd' * mapsize,
    221                "Copy-on-write memory map data not written correctly.")
    222         m.flush()
    223         self.assertEqual(open(TESTFN, "rb").read(), 'c'*mapsize,
    224                "Copy-on-write test data file should not be modified.")
    225         # Ensuring copy-on-write maps cannot be resized
    226         self.assertRaises(TypeError, m.resize, 2*mapsize)
    227         f.close()
    228         del m, f
    229 
    230         # Ensuring invalid access parameter raises exception
    231         f = open(TESTFN, "r+b")
    232         self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, access=4)
    233         f.close()
    234 
    235         if os.name == "posix":
    236             # Try incompatible flags, prot and access parameters.
    237             f = open(TESTFN, "r+b")
    238             self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize,
    239                               flags=mmap.MAP_PRIVATE,
    240                               prot=mmap.PROT_READ, access=mmap.ACCESS_WRITE)
    241             f.close()
    242 
    243             # Try writing with PROT_EXEC and without PROT_WRITE
    244             prot = mmap.PROT_READ | getattr(mmap, 'PROT_EXEC', 0)
    245             with open(TESTFN, "r+b") as f:
    246                 m = mmap.mmap(f.fileno(), mapsize, prot=prot)
    247                 self.assertRaises(TypeError, m.write, b"abcdef")
    248                 self.assertRaises(TypeError, m.write_byte, 0)
    249                 m.close()
    250 
    251     def test_bad_file_desc(self):
    252         # Try opening a bad file descriptor...
    253         self.assertRaises(mmap.error, mmap.mmap, -2, 4096)
    254 
    255     def test_tougher_find(self):
    256         # Do a tougher .find() test.  SF bug 515943 pointed out that, in 2.2,
    257         # searching for data with embedded \0 bytes didn't work.
    258         f = open(TESTFN, 'w+')
    259 
    260         data = 'aabaac\x00deef\x00\x00aa\x00'
    261         n = len(data)
    262         f.write(data)
    263         f.flush()
    264         m = mmap.mmap(f.fileno(), n)
    265         f.close()
    266 
    267         for start in range(n+1):
    268             for finish in range(start, n+1):
    269                 slice = data[start : finish]
    270                 self.assertEqual(m.find(slice), data.find(slice))
    271                 self.assertEqual(m.find(slice + 'x'), -1)
    272         m.close()
    273 
    274     def test_find_end(self):
    275         # test the new 'end' parameter works as expected
    276         f = open(TESTFN, 'w+')
    277         data = 'one two ones'
    278         n = len(data)
    279         f.write(data)
    280         f.flush()
    281         m = mmap.mmap(f.fileno(), n)
    282         f.close()
    283 
    284         self.assertEqual(m.find('one'), 0)
    285         self.assertEqual(m.find('ones'), 8)
    286         self.assertEqual(m.find('one', 0, -1), 0)
    287         self.assertEqual(m.find('one', 1), 8)
    288         self.assertEqual(m.find('one', 1, -1), 8)
    289         self.assertEqual(m.find('one', 1, -2), -1)
    290 
    291 
    292     def test_rfind(self):
    293         # test the new 'end' parameter works as expected
    294         f = open(TESTFN, 'w+')
    295         data = 'one two ones'
    296         n = len(data)
    297         f.write(data)
    298         f.flush()
    299         m = mmap.mmap(f.fileno(), n)
    300         f.close()
    301 
    302         self.assertEqual(m.rfind('one'), 8)
    303         self.assertEqual(m.rfind('one '), 0)
    304         self.assertEqual(m.rfind('one', 0, -1), 8)
    305         self.assertEqual(m.rfind('one', 0, -2), 0)
    306         self.assertEqual(m.rfind('one', 1, -1), 8)
    307         self.assertEqual(m.rfind('one', 1, -2), -1)
    308 
    309 
    310     def test_double_close(self):
    311         # make sure a double close doesn't crash on Solaris (Bug# 665913)
    312         f = open(TESTFN, 'w+')
    313 
    314         f.write(2**16 * 'a') # Arbitrary character
    315         f.close()
    316 
    317         f = open(TESTFN)
    318         mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ)
    319         mf.close()
    320         mf.close()
    321         f.close()
    322 
    323     @unittest.skipUnless(hasattr(os, "stat"), "needs os.stat()")
    324     def test_entire_file(self):
    325         # test mapping of entire file by passing 0 for map length
    326         f = open(TESTFN, "w+")
    327 
    328         f.write(2**16 * 'm') # Arbitrary character
    329         f.close()
    330 
    331         f = open(TESTFN, "rb+")
    332         mf = mmap.mmap(f.fileno(), 0)
    333         self.assertEqual(len(mf), 2**16, "Map size should equal file size.")
    334         self.assertEqual(mf.read(2**16), 2**16 * "m")
    335         mf.close()
    336         f.close()
    337 
    338     @unittest.skipUnless(hasattr(os, "stat"), "needs os.stat()")
    339     def test_length_0_offset(self):
    340         # Issue #10916: test mapping of remainder of file by passing 0 for
    341         # map length with an offset doesn't cause a segfault.
    342         # NOTE: allocation granularity is currently 65536 under Win64,
    343         # and therefore the minimum offset alignment.
    344         with open(TESTFN, "wb") as f:
    345             f.write((65536 * 2) * b'm') # Arbitrary character
    346 
    347         with open(TESTFN, "rb") as f:
    348             mf = mmap.mmap(f.fileno(), 0, offset=65536, access=mmap.ACCESS_READ)
    349             try:
    350                 self.assertRaises(IndexError, mf.__getitem__, 80000)
    351             finally:
    352                 mf.close()
    353 
    354     @unittest.skipUnless(hasattr(os, "stat"), "needs os.stat()")
    355     def test_length_0_large_offset(self):
    356         # Issue #10959: test mapping of a file by passing 0 for
    357         # map length with a large offset doesn't cause a segfault.
    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 
    365     def test_move(self):
    366         # make move works everywhere (64-bit format problem earlier)
    367         f = open(TESTFN, 'w+')
    368 
    369         f.write("ABCDEabcde") # Arbitrary character
    370         f.flush()
    371 
    372         mf = mmap.mmap(f.fileno(), 10)
    373         mf.move(5, 0, 5)
    374         self.assertEqual(mf[:], "ABCDEABCDE", "Map move should have duplicated front 5")
    375         mf.close()
    376         f.close()
    377 
    378         # more excessive test
    379         data = "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 
    390         # 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
    398 
    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 
    404         m.close()
    405 
    406         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 
    414     def test_anonymous(self):
    415         # anonymous mmap.mmap(-1, PAGE)
    416         m = mmap.mmap(-1, PAGESIZE)
    417         for x in xrange(PAGESIZE):
    418             self.assertEqual(m[x], '\0', "anonymously mmap'ed contents should be zero")
    419 
    420         for x in xrange(PAGESIZE):
    421             m[x] = ch = chr(x & 255)
    422             self.assertEqual(m[x], ch)
    423 
    424     def test_extended_getslice(self):
    425         # Test extended slicing by comparing with list slicing.
    426         s = "".join(chr(c) for c in reversed(range(256)))
    427         m = mmap.mmap(-1, len(s))
    428         m[:] = s
    429         self.assertEqual(m[:], s)
    430         indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
    431         for start in indices:
    432             for stop in indices:
    433                 # Skip step 0 (invalid)
    434                 for step in indices[1:]:
    435                     self.assertEqual(m[start:stop:step],
    436                                      s[start:stop:step])
    437 
    438     def test_extended_set_del_slice(self):
    439         # Test extended slicing by comparing with list slicing.
    440         s = "".join(chr(c) for c in reversed(range(256)))
    441         m = mmap.mmap(-1, len(s))
    442         indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
    443         for start in indices:
    444             for stop in indices:
    445                 # Skip invalid step 0
    446                 for step in indices[1:]:
    447                     m[:] = s
    448                     self.assertEqual(m[:], s)
    449                     L = list(s)
    450                     # Make sure we have a slice of exactly the right length,
    451                     # but with different data.
    452                     data = L[start:stop:step]
    453                     data = "".join(reversed(data))
    454                     L[start:stop:step] = data
    455                     m[start:stop:step] = data
    456                     self.assertEqual(m[:], "".join(L))
    457 
    458     def make_mmap_file (self, f, halfsize):
    459         # Write 2 pages worth of data to the file
    460         f.write ('\0' * halfsize)
    461         f.write ('foo')
    462         f.write ('\0' * (halfsize - 3))
    463         f.flush ()
    464         return mmap.mmap (f.fileno(), 0)
    465 
    466     def test_empty_file (self):
    467         f = open (TESTFN, 'w+b')
    468         f.close()
    469         with open(TESTFN, "rb") as f :
    470             self.assertRaisesRegexp(ValueError,
    471                                    "cannot mmap an empty file",
    472                                    mmap.mmap, f.fileno(), 0,
    473                                    access=mmap.ACCESS_READ)
    474 
    475     def test_offset (self):
    476         f = open (TESTFN, 'w+b')
    477 
    478         try: # unlink TESTFN no matter what
    479             halfsize = mmap.ALLOCATIONGRANULARITY
    480             m = self.make_mmap_file (f, halfsize)
    481             m.close ()
    482             f.close ()
    483 
    484             mapsize = halfsize * 2
    485             # Try invalid offset
    486             f = open(TESTFN, "r+b")
    487             for offset in [-2, -1, None]:
    488                 try:
    489                     m = mmap.mmap(f.fileno(), mapsize, offset=offset)
    490                     self.assertEqual(0, 1)
    491                 except (ValueError, TypeError, OverflowError):
    492                     pass
    493                 else:
    494                     self.assertEqual(0, 0)
    495             f.close()
    496 
    497             # Try valid offset, hopefully 8192 works on all OSes
    498             f = open(TESTFN, "r+b")
    499             m = mmap.mmap(f.fileno(), mapsize - halfsize, offset=halfsize)
    500             self.assertEqual(m[0:3], 'foo')
    501             f.close()
    502 
    503             # Try resizing map
    504             try:
    505                 m.resize(512)
    506             except SystemError:
    507                 pass
    508             else:
    509                 # resize() is supported
    510                 self.assertEqual(len(m), 512)
    511                 # Check that we can no longer seek beyond the new size.
    512                 self.assertRaises(ValueError, m.seek, 513, 0)
    513                 # Check that the content is not changed
    514                 self.assertEqual(m[0:3], 'foo')
    515 
    516                 # Check that the underlying file is truncated too
    517                 f = open(TESTFN)
    518                 f.seek(0, 2)
    519                 self.assertEqual(f.tell(), halfsize + 512)
    520                 f.close()
    521                 self.assertEqual(m.size(), halfsize + 512)
    522 
    523             m.close()
    524 
    525         finally:
    526             f.close()
    527             try:
    528                 os.unlink(TESTFN)
    529             except OSError:
    530                 pass
    531 
    532     def test_subclass(self):
    533         class anon_mmap(mmap.mmap):
    534             def __new__(klass, *args, **kwargs):
    535                 return mmap.mmap.__new__(klass, -1, *args, **kwargs)
    536         anon_mmap(PAGESIZE)
    537 
    538     @unittest.skipUnless(hasattr(mmap, 'PROT_READ'), "needs mmap.PROT_READ")
    539     def test_prot_readonly(self):
    540         mapsize = 10
    541         open(TESTFN, "wb").write("a"*mapsize)
    542         f = open(TESTFN, "rb")
    543         m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ)
    544         self.assertRaises(TypeError, m.write, "foo")
    545         f.close()
    546 
    547     def test_error(self):
    548         self.assertTrue(issubclass(mmap.error, EnvironmentError))
    549         self.assertIn("mmap.error", str(mmap.error))
    550 
    551     def test_io_methods(self):
    552         data = "0123456789"
    553         open(TESTFN, "wb").write("x"*len(data))
    554         f = open(TESTFN, "r+b")
    555         m = mmap.mmap(f.fileno(), len(data))
    556         f.close()
    557         # Test write_byte()
    558         for i in xrange(len(data)):
    559             self.assertEqual(m.tell(), i)
    560             m.write_byte(data[i])
    561             self.assertEqual(m.tell(), i+1)
    562         self.assertRaises(ValueError, m.write_byte, "x")
    563         self.assertEqual(m[:], data)
    564         # Test read_byte()
    565         m.seek(0)
    566         for i in xrange(len(data)):
    567             self.assertEqual(m.tell(), i)
    568             self.assertEqual(m.read_byte(), data[i])
    569             self.assertEqual(m.tell(), i+1)
    570         self.assertRaises(ValueError, m.read_byte)
    571         # Test read()
    572         m.seek(3)
    573         self.assertEqual(m.read(3), "345")
    574         self.assertEqual(m.tell(), 6)
    575         # Test write()
    576         m.seek(3)
    577         m.write("bar")
    578         self.assertEqual(m.tell(), 6)
    579         self.assertEqual(m[:], "012bar6789")
    580         m.seek(8)
    581         self.assertRaises(ValueError, m.write, "bar")
    582 
    583     @unittest.skipUnless(os.name == 'nt', 'requires Windows')
    584     def test_tagname(self):
    585         data1 = "0123456789"
    586         data2 = "abcdefghij"
    587         assert len(data1) == len(data2)
    588 
    589         # Test same tag
    590         m1 = mmap.mmap(-1, len(data1), tagname="foo")
    591         m1[:] = data1
    592         m2 = mmap.mmap(-1, len(data2), tagname="foo")
    593         m2[:] = data2
    594         self.assertEqual(m1[:], data2)
    595         self.assertEqual(m2[:], data2)
    596         m2.close()
    597         m1.close()
    598 
    599         # Test different tag
    600         m1 = mmap.mmap(-1, len(data1), tagname="foo")
    601         m1[:] = data1
    602         m2 = mmap.mmap(-1, len(data2), tagname="boo")
    603         m2[:] = data2
    604         self.assertEqual(m1[:], data1)
    605         self.assertEqual(m2[:], data2)
    606         m2.close()
    607         m1.close()
    608 
    609     @cpython_only
    610     @unittest.skipUnless(os.name == 'nt', 'requires Windows')
    611     def test_sizeof(self):
    612         m1 = mmap.mmap(-1, 100)
    613         tagname = "foo"
    614         m2 = mmap.mmap(-1, 100, tagname=tagname)
    615         self.assertEqual(sys.getsizeof(m2),
    616                          sys.getsizeof(m1) + len(tagname) + 1)
    617 
    618     @unittest.skipUnless(os.name == 'nt', 'requires Windows')
    619     def test_crasher_on_windows(self):
    620         # Should not crash (Issue 1733986)
    621         m = mmap.mmap(-1, 1000, tagname="foo")
    622         try:
    623             mmap.mmap(-1, 5000, tagname="foo")[:] # same tagname, but larger size
    624         except:
    625             pass
    626         m.close()
    627 
    628         # Should not crash (Issue 5385)
    629         open(TESTFN, "wb").write("x"*10)
    630         f = open(TESTFN, "r+b")
    631         m = mmap.mmap(f.fileno(), 0)
    632         f.close()
    633         try:
    634             m.resize(0) # will raise WindowsError
    635         except:
    636             pass
    637         try:
    638             m[:]
    639         except:
    640             pass
    641         m.close()
    642 
    643     @unittest.skipUnless(os.name == 'nt', 'requires Windows')
    644     def test_invalid_descriptor(self):
    645         # socket file descriptors are valid, but out of range
    646         # for _get_osfhandle, causing a crash when validating the
    647         # parameters to _get_osfhandle.
    648         s = socket.socket()
    649         try:
    650             with self.assertRaises(mmap.error):
    651                 m = mmap.mmap(s.fileno(), 10)
    652         finally:
    653             s.close()
    654 
    655     @unittest.skipIf(os.name == 'nt', 'cannot resize anonymous mmaps on Windows')
    656     def test_resize_past_pos(self):
    657         m = mmap.mmap(-1, 8192)
    658         self.addCleanup(m.close)
    659         m.read(5000)
    660         try:
    661             m.resize(4096)
    662         except SystemError:
    663             self.skipTest("resizing not supported")
    664         self.assertEqual(m.read(14), '')
    665         self.assertRaises(ValueError, m.read_byte)
    666         self.assertRaises(ValueError, m.write_byte, 'b')
    667         self.assertRaises(ValueError, m.write, 'abc')
    668 
    669     def test_concat_repeat_exception(self):
    670         m = mmap.mmap(-1, 16)
    671         with self.assertRaises(TypeError):
    672             m + m
    673         with self.assertRaises(TypeError):
    674             m * 2
    675 
    676 
    677 class LargeMmapTests(unittest.TestCase):
    678 
    679     def setUp(self):
    680         unlink(TESTFN)
    681 
    682     def tearDown(self):
    683         unlink(TESTFN)
    684 
    685     def _make_test_file(self, num_zeroes, tail):
    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         f = open(TESTFN, 'w+b')
    690         try:
    691             f.seek(num_zeroes)
    692             f.write(tail)
    693             f.flush()
    694         except (IOError, OverflowError):
    695             f.close()
    696             raise unittest.SkipTest("filesystem does not have largefile support")
    697         return f
    698 
    699     def test_large_offset(self):
    700         with self._make_test_file(0x14FFFFFFF, b" ") as f:
    701             m = mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ)
    702             try:
    703                 self.assertEqual(m[0xFFFFFFF], b" ")
    704             finally:
    705                 m.close()
    706 
    707     def test_large_filesize(self):
    708         with self._make_test_file(0x17FFFFFFF, b" ") as f:
    709             if sys.maxsize < 0x180000000:
    710                 # On 32 bit platforms the file is larger than sys.maxsize so
    711                 # mapping the whole file should fail -- Issue #16743
    712                 with self.assertRaises(OverflowError):
    713                     mmap.mmap(f.fileno(), 0x180000000, access=mmap.ACCESS_READ)
    714                 with self.assertRaises(ValueError):
    715                     mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
    716             m = mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ)
    717             try:
    718                 self.assertEqual(m.size(), 0x180000000)
    719             finally:
    720                 m.close()
    721 
    722     # Issue 11277: mmap() with large (~4GB) sparse files crashes on OS X.
    723 
    724     def _test_around_boundary(self, boundary):
    725         tail = b'  DEARdear  '
    726         start = boundary - len(tail) // 2
    727         end = start + len(tail)
    728         with self._make_test_file(start, tail) as f:
    729             m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
    730             try:
    731                 self.assertEqual(m[start:end], tail)
    732             finally:
    733                 m.close()
    734 
    735     @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems")
    736     def test_around_2GB(self):
    737         self._test_around_boundary(_2G)
    738 
    739     @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems")
    740     def test_around_4GB(self):
    741         self._test_around_boundary(_4G)
    742 
    743 
    744 def test_main():
    745     run_unittest(MmapTests, LargeMmapTests)
    746 
    747 if __name__ == '__main__':
    748     test_main()
    749