PageRenderTime 47ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/SiRFLive/PythonStdLib/test/test_mmap.py

https://bitbucket.org/x893/sirflive
Python | 333 lines | 263 code | 44 blank | 26 comment | 71 complexity | 2c6c9852ff8c74dab8fd716df0a8b860 MD5 | raw file
  1. from test.test_support import verify, vereq, TESTFN
  2. import mmap
  3. import os, re
  4. PAGESIZE = mmap.PAGESIZE
  5. def test_both():
  6. "Test mmap module on Unix systems and Windows"
  7. # Create a file to be mmap'ed.
  8. if os.path.exists(TESTFN):
  9. os.unlink(TESTFN)
  10. f = open(TESTFN, 'w+')
  11. try: # unlink TESTFN no matter what
  12. # Write 2 pages worth of data to the file
  13. f.write('\0'* PAGESIZE)
  14. f.write('foo')
  15. f.write('\0'* (PAGESIZE-3) )
  16. f.flush()
  17. m = mmap.mmap(f.fileno(), 2 * PAGESIZE)
  18. f.close()
  19. # Simple sanity checks
  20. print type(m) # SF bug 128713: segfaulted on Linux
  21. print ' Position of foo:', m.find('foo') / float(PAGESIZE), 'pages'
  22. vereq(m.find('foo'), PAGESIZE)
  23. print ' Length of file:', len(m) / float(PAGESIZE), 'pages'
  24. vereq(len(m), 2*PAGESIZE)
  25. print ' Contents of byte 0:', repr(m[0])
  26. vereq(m[0], '\0')
  27. print ' Contents of first 3 bytes:', repr(m[0:3])
  28. vereq(m[0:3], '\0\0\0')
  29. # Modify the file's content
  30. print "\n Modifying file's content..."
  31. m[0] = '3'
  32. m[PAGESIZE +3: PAGESIZE +3+3] = 'bar'
  33. # Check that the modification worked
  34. print ' Contents of byte 0:', repr(m[0])
  35. vereq(m[0], '3')
  36. print ' Contents of first 3 bytes:', repr(m[0:3])
  37. vereq(m[0:3], '3\0\0')
  38. print ' Contents of second page:', repr(m[PAGESIZE-1 : PAGESIZE + 7])
  39. vereq(m[PAGESIZE-1 : PAGESIZE + 7], '\0foobar\0')
  40. m.flush()
  41. # Test doing a regular expression match in an mmap'ed file
  42. match = re.search('[A-Za-z]+', m)
  43. if match is None:
  44. print ' ERROR: regex match on mmap failed!'
  45. else:
  46. start, end = match.span(0)
  47. length = end - start
  48. print ' Regex match on mmap (page start, length of match):',
  49. print start / float(PAGESIZE), length
  50. vereq(start, PAGESIZE)
  51. vereq(end, PAGESIZE + 6)
  52. # test seeking around (try to overflow the seek implementation)
  53. m.seek(0,0)
  54. print ' Seek to zeroth byte'
  55. vereq(m.tell(), 0)
  56. m.seek(42,1)
  57. print ' Seek to 42nd byte'
  58. vereq(m.tell(), 42)
  59. m.seek(0,2)
  60. print ' Seek to last byte'
  61. vereq(m.tell(), len(m))
  62. print ' Try to seek to negative position...'
  63. try:
  64. m.seek(-1)
  65. except ValueError:
  66. pass
  67. else:
  68. verify(0, 'expected a ValueError but did not get it')
  69. print ' Try to seek beyond end of mmap...'
  70. try:
  71. m.seek(1,2)
  72. except ValueError:
  73. pass
  74. else:
  75. verify(0, 'expected a ValueError but did not get it')
  76. print ' Try to seek to negative position...'
  77. try:
  78. m.seek(-len(m)-1,2)
  79. except ValueError:
  80. pass
  81. else:
  82. verify(0, 'expected a ValueError but did not get it')
  83. # Try resizing map
  84. print ' Attempting resize()'
  85. try:
  86. m.resize(512)
  87. except SystemError:
  88. # resize() not supported
  89. # No messages are printed, since the output of this test suite
  90. # would then be different across platforms.
  91. pass
  92. else:
  93. # resize() is supported
  94. verify(len(m) == 512,
  95. "len(m) is %d, but expecting 512" % (len(m),) )
  96. # Check that we can no longer seek beyond the new size.
  97. try:
  98. m.seek(513,0)
  99. except ValueError:
  100. pass
  101. else:
  102. verify(0, 'Could seek beyond the new size')
  103. # Check that the underlying file is truncated too
  104. # (bug #728515)
  105. f = open(TESTFN)
  106. f.seek(0, 2)
  107. verify(f.tell() == 512, 'Underlying file not truncated')
  108. f.close()
  109. verify(m.size() == 512, 'New size not reflected in file')
  110. m.close()
  111. finally:
  112. try:
  113. f.close()
  114. except OSError:
  115. pass
  116. try:
  117. os.unlink(TESTFN)
  118. except OSError:
  119. pass
  120. # Test for "access" keyword parameter
  121. try:
  122. mapsize = 10
  123. print " Creating", mapsize, "byte test data file."
  124. open(TESTFN, "wb").write("a"*mapsize)
  125. print " Opening mmap with access=ACCESS_READ"
  126. f = open(TESTFN, "rb")
  127. m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_READ)
  128. verify(m[:] == 'a'*mapsize, "Readonly memory map data incorrect.")
  129. print " Ensuring that readonly mmap can't be slice assigned."
  130. try:
  131. m[:] = 'b'*mapsize
  132. except TypeError:
  133. pass
  134. else:
  135. verify(0, "Able to write to readonly memory map")
  136. print " Ensuring that readonly mmap can't be item assigned."
  137. try:
  138. m[0] = 'b'
  139. except TypeError:
  140. pass
  141. else:
  142. verify(0, "Able to write to readonly memory map")
  143. print " 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. verify(0, "Able to write to readonly memory map")
  151. print " Ensuring that readonly mmap can't be write_byte() to."
  152. try:
  153. m.seek(0,0)
  154. m.write_byte('d')
  155. except TypeError:
  156. pass
  157. else:
  158. verify(0, "Able to write to readonly memory map")
  159. print " Ensuring that readonly mmap can't be resized."
  160. try:
  161. m.resize(2*mapsize)
  162. except SystemError: # resize is not universally supported
  163. pass
  164. except TypeError:
  165. pass
  166. else:
  167. verify(0, "Able to resize readonly memory map")
  168. del m, f
  169. verify(open(TESTFN, "rb").read() == 'a'*mapsize,
  170. "Readonly memory map data file was modified")
  171. print " Opening mmap with size too big"
  172. import sys
  173. f = open(TESTFN, "r+b")
  174. try:
  175. m = mmap.mmap(f.fileno(), mapsize+1)
  176. except ValueError:
  177. # we do not expect a ValueError on Windows
  178. # CAUTION: This also changes the size of the file on disk, and
  179. # later tests assume that the length hasn't changed. We need to
  180. # repair that.
  181. if sys.platform.startswith('win'):
  182. verify(0, "Opening mmap with size+1 should work on Windows.")
  183. else:
  184. # we expect a ValueError on Unix, but not on Windows
  185. if not sys.platform.startswith('win'):
  186. verify(0, "Opening mmap with size+1 should raise ValueError.")
  187. m.close()
  188. f.close()
  189. if sys.platform.startswith('win'):
  190. # Repair damage from the resizing test.
  191. f = open(TESTFN, 'r+b')
  192. f.truncate(mapsize)
  193. f.close()
  194. print " Opening mmap with access=ACCESS_WRITE"
  195. f = open(TESTFN, "r+b")
  196. m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_WRITE)
  197. print " Modifying write-through memory map."
  198. m[:] = 'c'*mapsize
  199. verify(m[:] == 'c'*mapsize,
  200. "Write-through memory map memory not updated properly.")
  201. m.flush()
  202. m.close()
  203. f.close()
  204. f = open(TESTFN, 'rb')
  205. stuff = f.read()
  206. f.close()
  207. verify(stuff == 'c'*mapsize,
  208. "Write-through memory map data file not updated properly.")
  209. print " Opening mmap with access=ACCESS_COPY"
  210. f = open(TESTFN, "r+b")
  211. m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_COPY)
  212. print " Modifying copy-on-write memory map."
  213. m[:] = 'd'*mapsize
  214. verify(m[:] == 'd' * mapsize,
  215. "Copy-on-write memory map data not written correctly.")
  216. m.flush()
  217. verify(open(TESTFN, "rb").read() == 'c'*mapsize,
  218. "Copy-on-write test data file should not be modified.")
  219. try:
  220. print " Ensuring copy-on-write maps cannot be resized."
  221. m.resize(2*mapsize)
  222. except TypeError:
  223. pass
  224. else:
  225. verify(0, "Copy-on-write mmap resize did not raise exception.")
  226. del m, f
  227. try:
  228. print " Ensuring invalid access parameter raises exception."
  229. f = open(TESTFN, "r+b")
  230. m = mmap.mmap(f.fileno(), mapsize, access=4)
  231. except ValueError:
  232. pass
  233. else:
  234. verify(0, "Invalid access code should have raised exception.")
  235. if os.name == "posix":
  236. # Try incompatible flags, prot and access parameters.
  237. f = open(TESTFN, "r+b")
  238. try:
  239. m = mmap.mmap(f.fileno(), mapsize, flags=mmap.MAP_PRIVATE,
  240. prot=mmap.PROT_READ, access=mmap.ACCESS_WRITE)
  241. except ValueError:
  242. pass
  243. else:
  244. verify(0, "Incompatible parameters should raise ValueError.")
  245. f.close()
  246. finally:
  247. try:
  248. os.unlink(TESTFN)
  249. except OSError:
  250. pass
  251. print ' Try opening a bad file descriptor...'
  252. try:
  253. mmap.mmap(-1, 4096)
  254. except mmap.error:
  255. pass
  256. else:
  257. verify(0, 'expected a mmap.error but did not get it')
  258. # Do a tougher .find() test. SF bug 515943 pointed out that, in 2.2,
  259. # searching for data with embedded \0 bytes didn't work.
  260. f = open(TESTFN, 'w+')
  261. try: # unlink TESTFN no matter what
  262. data = 'aabaac\x00deef\x00\x00aa\x00'
  263. n = len(data)
  264. f.write(data)
  265. f.flush()
  266. m = mmap.mmap(f.fileno(), n)
  267. f.close()
  268. for start in range(n+1):
  269. for finish in range(start, n+1):
  270. slice = data[start : finish]
  271. vereq(m.find(slice), data.find(slice))
  272. vereq(m.find(slice + 'x'), -1)
  273. m.close()
  274. finally:
  275. os.unlink(TESTFN)
  276. # make sure a double close doesn't crash on Solaris (Bug# 665913)
  277. f = open(TESTFN, 'w+')
  278. try: # unlink TESTFN no matter what
  279. f.write(2**16 * 'a') # Arbitrary character
  280. f.close()
  281. f = open(TESTFN)
  282. mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ)
  283. mf.close()
  284. mf.close()
  285. f.close()
  286. finally:
  287. os.unlink(TESTFN)
  288. print ' Test passed'
  289. test_both()