text: from test.test_support import (TESTFN, run_unittest, import_module, unlink,
                                 requires, _2G, _4G)
  import unittest
  import os, re, itertools, socket, sys
  
  mmap = import_module('mmap')
  
  PAGESIZE = mmap.PAGESIZE
  
  class MmapTests(unittest.TestCase):
  
      def setUp(self):
          if os.path.exists(TESTFN):
              os.unlink(TESTFN)
  
      def tearDown(self):
          try:
              os.unlink(TESTFN)
          except OSError:
              pass
  
      def test_basic(self):
          # Test mmap module on Unix systems and Windows
  
          # Create a file to be mmap'ed.
          f = open(TESTFN, 'w+')
          try:
              # Write 2 pages worth of data to the file
              f.write('\0'* PAGESIZE)
              f.write('foo')
              f.write('\0'* (PAGESIZE-3) )
              f.flush()
              m = mmap.mmap(f.fileno(), 2 * PAGESIZE)
              f.close()
  
              # Simple sanity checks
  
              tp = str(type(m))  # SF bug 128713:  segfaulted on Linux
              self.assertEqual(m.find('foo'), PAGESIZE)
  
              self.assertEqual(len(m), 2*PAGESIZE)
  
              self.assertEqual(m[0], '\0')
              self.assertEqual(m[0:3], '\0\0\0')
  
              # Shouldn't crash on boundary (Issue #5292)
              self.assertRaises(IndexError, m.__getitem__, len(m))
              self.assertRaises(IndexError, m.__setitem__, len(m), '\0')
  
              # Modify the file's content
              m[0] = '3'
              m[PAGESIZE +3: PAGESIZE +3+3] = 'bar'
  
              # Check that the modification worked
              self.assertEqual(m[0], '3')
              self.assertEqual(m[0:3], '3\0\0')
              self.assertEqual(m[PAGESIZE-1 : PAGESIZE + 7], '\0foobar\0')
  
              m.flush()
  
              # Test doing a regular expression match in an mmap'ed file
              match = re.search('[A-Za-z]+', m)
              if match is None:
                  self.fail('regex match on mmap failed!')
              else:
                  start, end = match.span(0)
                  length = end - start
  
                  self.assertEqual(start, PAGESIZE)
                  self.assertEqual(end, PAGESIZE + 6)
  
              # test seeking around (try to overflow the seek implementation)
              m.seek(0,0)
              self.assertEqual(m.tell(), 0)
              m.seek(42,1)
              self.assertEqual(m.tell(), 42)
              m.seek(0,2)
              self.assertEqual(m.tell(), len(m))
  
              # Try to seek to negative position...
              self.assertRaises(ValueError, m.seek, -1)
  
              # Try to seek beyond end of mmap...
              self.assertRaises(ValueError, m.seek, 1, 2)
  
              # Try to seek to negative position...
              self.assertRaises(ValueError, m.seek, -len(m)-1, 2)
  
              # Try resizing map
              try:
                  m.resize(512)
              except SystemError:
                  # resize() not supported
                  # No messages are printed, since the output of this test suite
                  # would then be different across platforms.
                  pass
              else:
                  # resize() is supported
                  self.assertEqual(len(m), 512)
                  # Check that we can no longer seek beyond the new size.
                  self.assertRaises(ValueError, m.seek, 513, 0)
  
                  # Check that the underlying file is truncated too
                  # (bug #728515)
                  f = open(TESTFN)
                  f.seek(0, 2)
                  self.assertEqual(f.tell(), 512)
                  f.close()
                  self.assertEqual(m.size(), 512)
  
              m.close()
  
          finally:
              try:
                  f.close()
              except OSError:
                  pass
  
      def test_access_parameter(self):
          # Test for "access" keyword parameter
          mapsize = 10
          open(TESTFN, "wb").write("a"*mapsize)
          f = open(TESTFN, "rb")
          m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_READ)
          self.assertEqual(m[:], 'a'*mapsize, "Readonly memory map data incorrect.")
  
          # Ensuring that readonly mmap can't be slice assigned
          try:
              m[:] = 'b'*mapsize
          except TypeError:
              pass
          else:
              self.fail("Able to write to readonly memory map")
  
          # Ensuring that readonly mmap can't be item assigned
          try:
              m[0] = 'b'
          except TypeError:
              pass
          else:
              self.fail("Able to write to readonly memory map")
  
          # Ensuring that readonly mmap can't be write() to
          try:
              m.seek(0,0)
              m.write('abc')
          except TypeError:
              pass
          else:
              self.fail("Able to write to readonly memory map")
  
          # Ensuring that readonly mmap can't be write_byte() to
          try:
              m.seek(0,0)
              m.write_byte('d')
          except TypeError:
              pass
          else:
              self.fail("Able to write to readonly memory map")
  
          # Ensuring that readonly mmap can't be resized
          try:
              m.resize(2*mapsize)
          except SystemError:   # resize is not universally supported
              pass
          except TypeError:
              pass
          else:
              self.fail("Able to resize readonly memory map")
          f.close()
          del m, f
          self.assertEqual(open(TESTFN, "rb").read(), 'a'*mapsize,
                 "Readonly memory map data file was modified")
  
          # Opening mmap with size too big
          import sys
          f = open(TESTFN, "r+b")
          try:
              m = mmap.mmap(f.fileno(), mapsize+1)
          except ValueError:
              # we do not expect a ValueError on Windows
              # CAUTION:  This also changes the size of the file on disk, and
              # later tests assume that the length hasn't changed.  We need to
              # repair that.
              if sys.platform.startswith('win'):
                  self.fail("Opening mmap with size+1 should work on Windows.")
          else:
              # we expect a ValueError on Unix, but not on Windows
              if not sys.platform.startswith('win'):
                  self.fail("Opening mmap with size+1 should raise ValueError.")
              m.close()
          f.close()
          if sys.platform.startswith('win'):
              # Repair damage from the resizing test.
              f = open(TESTFN, 'r+b')
              f.truncate(mapsize)
              f.close()
  
          # Opening mmap with access=ACCESS_WRITE
          f = open(TESTFN, "r+b")
          m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_WRITE)
          # Modifying write-through memory map
          m[:] = 'c'*mapsize
          self.assertEqual(m[:], 'c'*mapsize,
                 "Write-through memory map memory not updated properly.")
          m.flush()
          m.close()
          f.close()
          f = open(TESTFN, 'rb')
          stuff = f.read()
          f.close()
          self.assertEqual(stuff, 'c'*mapsize,
                 "Write-through memory map data file not updated properly.")
  
          # Opening mmap with access=ACCESS_COPY
          f = open(TESTFN, "r+b")
          m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_COPY)
          # Modifying copy-on-write memory map
          m[:] = 'd'*mapsize
          self.assertEqual(m[:], 'd' * mapsize,
                 "Copy-on-write memory map data not written correctly.")
          m.flush()
          self.assertEqual(open(TESTFN, "rb").read(), 'c'*mapsize,
                 "Copy-on-write test data file should not be modified.")
          # Ensuring copy-on-write maps cannot be resized
          self.assertRaises(TypeError, m.resize, 2*mapsize)
          f.close()
          del m, f
  
          # Ensuring invalid access parameter raises exception
          f = open(TESTFN, "r+b")
          self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, access=4)
          f.close()
  
          if os.name == "posix":
              # Try incompatible flags, prot and access parameters.
              f = open(TESTFN, "r+b")
              self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize,
                                flags=mmap.MAP_PRIVATE,
                                prot=mmap.PROT_READ, access=mmap.ACCESS_WRITE)
              f.close()
  
              # Try writing with PROT_EXEC and without PROT_WRITE
              prot = mmap.PROT_READ | getattr(mmap, 'PROT_EXEC', 0)
              with open(TESTFN, "r+b") as f:
                  m = mmap.mmap(f.fileno(), mapsize, prot=prot)
                  self.assertRaises(TypeError, m.write, b"abcdef")
                  self.assertRaises(TypeError, m.write_byte, 0)
                  m.close()
  
      def test_bad_file_desc(self):
          # Try opening a bad file descriptor...
          self.assertRaises(mmap.error, mmap.mmap, -2, 4096)
  
      def test_tougher_find(self):
          # Do a tougher .find() test.  SF bug 515943 pointed out that, in 2.2,
          # searching for data with embedded \0 bytes didn't work.
          f = open(TESTFN, 'w+')
  
          data = 'aabaac\x00deef\x00\x00aa\x00'
          n = len(data)
          f.write(data)
          f.flush()
          m = mmap.mmap(f.fileno(), n)
          f.close()
  
          for start in range(n+1):
              for finish in range(start, n+1):
                  slice = data[start : finish]
                  self.assertEqual(m.find(slice), data.find(slice))
                  self.assertEqual(m.find(slice + 'x'), -1)
          m.close()
  
      def test_find_end(self):
          # test the new 'end' parameter works as expected
          f = open(TESTFN, 'w+')
          data = 'one two ones'
          n = len(data)
          f.write(data)
          f.flush()
          m = mmap.mmap(f.fileno(), n)
          f.close()
  
          self.assertEqual(m.find('one'), 0)
          self.assertEqual(m.find('ones'), 8)
          self.assertEqual(m.find('one', 0, -1), 0)
          self.assertEqual(m.find('one', 1), 8)
          self.assertEqual(m.find('one', 1, -1), 8)
          self.assertEqual(m.find('one', 1, -2), -1)
  
  
      def test_rfind(self):
          # test the new 'end' parameter works as expected
          f = open(TESTFN, 'w+')
          data = 'one two ones'
          n = len(data)
          f.write(data)
          f.flush()
          m = mmap.mmap(f.fileno(), n)
          f.close()
  
          self.assertEqual(m.rfind('one'), 8)
          self.assertEqual(m.rfind('one '), 0)
          self.assertEqual(m.rfind('one', 0, -1), 8)
          self.assertEqual(m.rfind('one', 0, -2), 0)
          self.assertEqual(m.rfind('one', 1, -1), 8)
          self.assertEqual(m.rfind('one', 1, -2), -1)
  
  
      def test_double_close(self):
          # make sure a double close doesn't crash on Solaris (Bug# 665913)
          f = open(TESTFN, 'w+')
  
          f.write(2**16 * 'a') # Arbitrary character
          f.close()
  
          f = open(TESTFN)
          mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ)
          mf.close()
          mf.close()
          f.close()
  
      def test_entire_file(self):
          # test mapping of entire file by passing 0 for map length
          if hasattr(os, "stat"):
              f = open(TESTFN, "w+")
  
              f.write(2**16 * 'm') # Arbitrary character
              f.close()
  
              f = open(TESTFN, "rb+")
              mf = mmap.mmap(f.fileno(), 0)
              self.assertEqual(len(mf), 2**16, "Map size should equal file size.")
              self.assertEqual(mf.read(2**16), 2**16 * "m")
              mf.close()
              f.close()
  
      def test_length_0_offset(self):
          # Issue #10916: test mapping of remainder of file by passing 0 for
          # map length with an offset doesn't cause a segfault.
          if not hasattr(os, "stat"):
              self.skipTest("needs os.stat")
          # NOTE: allocation granularity is currently 65536 under Win64,
          # and therefore the minimum offset alignment.
          with open(TESTFN, "wb") as f:
              f.write((65536 * 2) * b'm') # Arbitrary character
  
          with open(TESTFN, "rb") as f:
              mf = mmap.mmap(f.fileno(), 0, offset=65536, access=mmap.ACCESS_READ)
              try:
                  self.assertRaises(IndexError, mf.__getitem__, 80000)
              finally:
                  mf.close()
  
      def test_length_0_large_offset(self):
          # Issue #10959: test mapping of a file by passing 0 for
          # map length with a large offset doesn't cause a segfault.
          if not hasattr(os, "stat"):
              self.skipTest("needs os.stat")
  
          with open(TESTFN, "wb") as f:
              f.write(115699 * b'm') # Arbitrary character
  
          with open(TESTFN, "w+b") as f:
              self.assertRaises(ValueError, mmap.mmap, f.fileno(), 0,
                                offset=2147418112)
  
      def test_move(self):
          # make move works everywhere (64-bit format problem earlier)
          f = open(TESTFN, 'w+')
  
          f.write("ABCDEabcde") # Arbitrary character
          f.flush()
  
          mf = mmap.mmap(f.fileno(), 10)
          mf.move(5, 0, 5)
          self.assertEqual(mf[:], "ABCDEABCDE", "Map move should have duplicated front 5")
          mf.close()
          f.close()
  
          # more excessive test
          data = "0123456789"
          for dest in range(len(data)):
              for src in range(len(data)):
                  for count in range(len(data) - max(dest, src)):
                      expected = data[:dest] + data[src:src+count] + data[dest+count:]
                      m = mmap.mmap(-1, len(data))
                      m[:] = data
                      m.move(dest, src, count)
                      self.assertEqual(m[:], expected)
                      m.close()
  
          # segfault test (Issue 5387)
          m = mmap.mmap(-1, 100)
          offsets = [-100, -1, 0, 1, 100]
          for source, dest, size in itertools.product(offsets, offsets, offsets):
              try:
                  m.move(source, dest, size)
              except ValueError:
                  pass
  
          offsets = [(-1, -1, -1), (-1, -1, 0), (-1, 0, -1), (0, -1, -1),
                     (-1, 0, 0), (0, -1, 0), (0, 0, -1)]
          for source, dest, size in offsets:
              self.assertRaises(ValueError, m.move, source, dest, size)
  
          m.close()
  
          m = mmap.mmap(-1, 1) # single byte
          self.assertRaises(ValueError, m.move, 0, 0, 2)
          self.assertRaises(ValueError, m.move, 1, 0, 1)
          self.assertRaises(ValueError, m.move, 0, 1, 1)
          m.move(0, 0, 1)
          m.move(0, 0, 0)
  
  
      def test_anonymous(self):
          # anonymous mmap.mmap(-1, PAGE)
          m = mmap.mmap(-1, PAGESIZE)
          for x in xrange(PAGESIZE):
              self.assertEqual(m[x], '\0', "anonymously mmap'ed contents should be zero")
  
          for x in xrange(PAGESIZE):
              m[x] = ch = chr(x & 255)
              self.assertEqual(m[x], ch)
  
      def test_extended_getslice(self):
          # Test extended slicing by comparing with list slicing.
          s = "".join(chr(c) for c in reversed(range(256)))
          m = mmap.mmap(-1, len(s))
          m[:] = s
          self.assertEqual(m[:], s)
          indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
          for start in indices:
              for stop in indices:
                  # Skip step 0 (invalid)
                  for step in indices[1:]:
                      self.assertEqual(m[start:stop:step],
                                       s[start:stop:step])
  
      def test_extended_set_del_slice(self):
          # Test extended slicing by comparing with list slicing.
          s = "".join(chr(c) for c in reversed(range(256)))
          m = mmap.mmap(-1, len(s))
          indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300)
          for start in indices:
              for stop in indices:
                  # Skip invalid step 0
                  for step in indices[1:]:
                      m[:] = s
                      self.assertEqual(m[:], s)
                      L = list(s)
                      # Make sure we have a slice of exactly the right length,
                      # but with different data.
                      data = L[start:stop:step]
                      data = "".join(reversed(data))
                      L[start:stop:step] = data
                      m[start:stop:step] = data
                      self.assertEqual(m[:], "".join(L))
  
      def make_mmap_file (self, f, halfsize):
          # Write 2 pages worth of data to the file
          f.write ('\0' * halfsize)
          f.write ('foo')
          f.write ('\0' * (halfsize - 3))
          f.flush ()
          return mmap.mmap (f.fileno(), 0)
  
      def test_offset (self):
          f = open (TESTFN, 'w+b')
  
          try: # unlink TESTFN no matter what
              halfsize = mmap.ALLOCATIONGRANULARITY
              m = self.make_mmap_file (f, halfsize)
              m.close ()
              f.close ()
  
              mapsize = halfsize * 2
              # Try invalid offset
              f = open(TESTFN, "r+b")
              for offset in [-2, -1, None]:
                  try:
                      m = mmap.mmap(f.fileno(), mapsize, offset=offset)
                      self.assertEqual(0, 1)
                  except (ValueError, TypeError, OverflowError):
                      pass
                  else:
                      self.assertEqual(0, 0)
              f.close()
  
              # Try valid offset, hopefully 8192 works on all OSes
              f = open(TESTFN, "r+b")
              m = mmap.mmap(f.fileno(), mapsize - halfsize, offset=halfsize)
              self.assertEqual(m[0:3], 'foo')
              f.close()
  
              # Try resizing map
              try:
                  m.resize(512)
              except SystemError:
                  pass
              else:
                  # resize() is supported
                  self.assertEqual(len(m), 512)
                  # Check that we can no longer seek beyond the new size.
                  self.assertRaises(ValueError, m.seek, 513, 0)
                  # Check that the content is not changed
                  self.assertEqual(m[0:3], 'foo')
  
                  # Check that the underlying file is truncated too
                  f = open(TESTFN)
                  f.seek(0, 2)
                  self.assertEqual(f.tell(), halfsize + 512)
                  f.close()
                  self.assertEqual(m.size(), halfsize + 512)
  
              m.close()
  
          finally:
              f.close()
              try:
                  os.unlink(TESTFN)
              except OSError:
                  pass
  
      def test_subclass(self):
          class anon_mmap(mmap.mmap):
              def __new__(klass, *args, **kwargs):
                  return mmap.mmap.__new__(klass, -1, *args, **kwargs)
          anon_mmap(PAGESIZE)
  
      def test_prot_readonly(self):
          if not hasattr(mmap, 'PROT_READ'):
              return
          mapsize = 10
          open(TESTFN, "wb").write("a"*mapsize)
          f = open(TESTFN, "rb")
          m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ)
          self.assertRaises(TypeError, m.write, "foo")
          f.close()
  
      def test_error(self):
          self.assertTrue(issubclass(mmap.error, EnvironmentError))
          self.assertIn("mmap.error", str(mmap.error))
  
      def test_io_methods(self):
          data = "0123456789"
          open(TESTFN, "wb").write("x"*len(data))
          f = open(TESTFN, "r+b")
          m = mmap.mmap(f.fileno(), len(data))
          f.close()
          # Test write_byte()
          for i in xrange(len(data)):
              self.assertEqual(m.tell(), i)
              m.write_byte(data[i])
              self.assertEqual(m.tell(), i+1)
          self.assertRaises(ValueError, m.write_byte, "x")
          self.assertEqual(m[:], data)
          # Test read_byte()
          m.seek(0)
          for i in xrange(len(data)):
              self.assertEqual(m.tell(), i)
              self.assertEqual(m.read_byte(), data[i])
              self.assertEqual(m.tell(), i+1)
          self.assertRaises(ValueError, m.read_byte)
          # Test read()
          m.seek(3)
          self.assertEqual(m.read(3), "345")
          self.assertEqual(m.tell(), 6)
          # Test write()
          m.seek(3)
          m.write("bar")
          self.assertEqual(m.tell(), 6)
          self.assertEqual(m[:], "012bar6789")
          m.seek(8)
          self.assertRaises(ValueError, m.write, "bar")
  
      if os.name == 'nt':
          def test_tagname(self):
              data1 = "0123456789"
              data2 = "abcdefghij"
              assert len(data1) == len(data2)
  
              # Test same tag
              m1 = mmap.mmap(-1, len(data1), tagname="foo")
              m1[:] = data1
              m2 = mmap.mmap(-1, len(data2), tagname="foo")
              m2[:] = data2
              self.assertEqual(m1[:], data2)
              self.assertEqual(m2[:], data2)
              m2.close()
              m1.close()
  
              # Test different tag
              m1 = mmap.mmap(-1, len(data1), tagname="foo")
              m1[:] = data1
              m2 = mmap.mmap(-1, len(data2), tagname="boo")
              m2[:] = data2
              self.assertEqual(m1[:], data1)
              self.assertEqual(m2[:], data2)
              m2.close()
              m1.close()
  
          def test_crasher_on_windows(self):
              # Should not crash (Issue 1733986)
              m = mmap.mmap(-1, 1000, tagname="foo")
              try:
                  mmap.mmap(-1, 5000, tagname="foo")[:] # same tagname, but larger size
              except:
                  pass
              m.close()
  
              # Should not crash (Issue 5385)
              open(TESTFN, "wb").write("x"*10)
              f = open(TESTFN, "r+b")
              m = mmap.mmap(f.fileno(), 0)
              f.close()
              try:
                  m.resize(0) # will raise WindowsError
              except:
                  pass
              try:
                  m[:]
              except:
                  pass
              m.close()
  
          def test_invalid_descriptor(self):
              # socket file descriptors are valid, but out of range
              # for _get_osfhandle, causing a crash when validating the
              # parameters to _get_osfhandle.
              s = socket.socket()
              try:
                  with self.assertRaises(mmap.error):
                      m = mmap.mmap(s.fileno(), 10)
              finally:
                  s.close()
  
  
  class LargeMmapTests(unittest.TestCase):
  
      def setUp(self):
          unlink(TESTFN)
  
      def tearDown(self):
          unlink(TESTFN)
  
      def _make_test_file(self, num_zeroes, tail):
          if sys.platform[:3] == 'win' or sys.platform == 'darwin':
              requires('largefile',
                  'test requires %s bytes and a long time to run' % str(0x180000000))
          f = open(TESTFN, 'w+b')
          try:
              f.seek(num_zeroes)
              f.write(tail)
              f.flush()
          except (IOError, OverflowError):
              f.close()
              raise unittest.SkipTest("filesystem does not have largefile support")
          return f
  
      def test_large_offset(self):
          with self._make_test_file(0x14FFFFFFF, b" ") as f:
              m = mmap.mmap(f.fileno(), 0, offset=0x140000000, access=mmap.ACCESS_READ)
              try:
                  self.assertEqual(m[0xFFFFFFF], b" ")
              finally:
                  m.close()
  
      def test_large_filesize(self):
          with self._make_test_file(0x17FFFFFFF, b" ") as f:
              m = mmap.mmap(f.fileno(), 0x10000, access=mmap.ACCESS_READ)
              try:
                  self.assertEqual(m.size(), 0x180000000)
              finally:
                  m.close()
  
      # Issue 11277: mmap() with large (~4GB) sparse files crashes on OS X.
  
      def _test_around_boundary(self, boundary):
          tail = b'  DEARdear  '
          start = boundary - len(tail) // 2
          end = start + len(tail)
          with self._make_test_file(start, tail) as f:
              m = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
              try:
                  self.assertEqual(m[start:end], tail)
              finally:
                  m.close()
  
      @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems")
      def test_around_2GB(self):
          self._test_around_boundary(_2G)
  
      @unittest.skipUnless(sys.maxsize > _4G, "test cannot run on 32-bit systems")
      def test_around_4GB(self):
          self._test_around_boundary(_4G)
  
  
  def test_main():
      run_unittest(MmapTests, LargeMmapTests)
  
  if __name__ == '__main__':
      test_main()
  