test_largefile.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. """Test largefile support on system where this makes sense.
  2. """
  3. from __future__ import print_function
  4. import os
  5. import stat
  6. import sys
  7. import unittest
  8. from test.test_support import run_unittest, TESTFN, verbose, requires, \
  9. unlink
  10. import io # C implementation of io
  11. import _pyio as pyio # Python implementation of io
  12. try:
  13. import signal
  14. # The default handler for SIGXFSZ is to abort the process.
  15. # By ignoring it, system calls exceeding the file size resource
  16. # limit will raise IOError instead of crashing the interpreter.
  17. oldhandler = signal.signal(signal.SIGXFSZ, signal.SIG_IGN)
  18. except (ImportError, AttributeError):
  19. pass
  20. # create >2GB file (2GB = 2147483648 bytes)
  21. size = 2500000000
  22. class LargeFileTest(unittest.TestCase):
  23. """Test that each file function works as expected for a large
  24. (i.e. > 2GB, do we have to check > 4GB) files.
  25. NOTE: the order of execution of the test methods is important! test_seek
  26. must run first to create the test file. File cleanup must also be handled
  27. outside the test instances because of this.
  28. """
  29. def test_seek(self):
  30. if verbose:
  31. print('create large file via seek (may be sparse file) ...')
  32. with self.open(TESTFN, 'wb') as f:
  33. f.write(b'z')
  34. f.seek(0)
  35. f.seek(size)
  36. f.write(b'a')
  37. f.flush()
  38. if verbose:
  39. print('check file size with os.fstat')
  40. self.assertEqual(os.fstat(f.fileno())[stat.ST_SIZE], size+1)
  41. def test_osstat(self):
  42. if verbose:
  43. print('check file size with os.stat')
  44. self.assertEqual(os.stat(TESTFN)[stat.ST_SIZE], size+1)
  45. def test_seek_read(self):
  46. if verbose:
  47. print('play around with seek() and read() with the built largefile')
  48. with self.open(TESTFN, 'rb') as f:
  49. self.assertEqual(f.tell(), 0)
  50. self.assertEqual(f.read(1), b'z')
  51. self.assertEqual(f.tell(), 1)
  52. f.seek(0)
  53. self.assertEqual(f.tell(), 0)
  54. f.seek(0, 0)
  55. self.assertEqual(f.tell(), 0)
  56. f.seek(42)
  57. self.assertEqual(f.tell(), 42)
  58. f.seek(42, 0)
  59. self.assertEqual(f.tell(), 42)
  60. f.seek(42, 1)
  61. self.assertEqual(f.tell(), 84)
  62. f.seek(0, 1)
  63. self.assertEqual(f.tell(), 84)
  64. f.seek(0, 2) # seek from the end
  65. self.assertEqual(f.tell(), size + 1 + 0)
  66. f.seek(-10, 2)
  67. self.assertEqual(f.tell(), size + 1 - 10)
  68. f.seek(-size-1, 2)
  69. self.assertEqual(f.tell(), 0)
  70. f.seek(size)
  71. self.assertEqual(f.tell(), size)
  72. # the 'a' that was written at the end of file above
  73. self.assertEqual(f.read(1), b'a')
  74. f.seek(-size-1, 1)
  75. self.assertEqual(f.read(1), b'z')
  76. self.assertEqual(f.tell(), 1)
  77. def test_lseek(self):
  78. if verbose:
  79. print('play around with os.lseek() with the built largefile')
  80. with self.open(TESTFN, 'rb') as f:
  81. self.assertEqual(os.lseek(f.fileno(), 0, 0), 0)
  82. self.assertEqual(os.lseek(f.fileno(), 42, 0), 42)
  83. self.assertEqual(os.lseek(f.fileno(), 42, 1), 84)
  84. self.assertEqual(os.lseek(f.fileno(), 0, 1), 84)
  85. self.assertEqual(os.lseek(f.fileno(), 0, 2), size+1+0)
  86. self.assertEqual(os.lseek(f.fileno(), -10, 2), size+1-10)
  87. self.assertEqual(os.lseek(f.fileno(), -size-1, 2), 0)
  88. self.assertEqual(os.lseek(f.fileno(), size, 0), size)
  89. # the 'a' that was written at the end of file above
  90. self.assertEqual(f.read(1), b'a')
  91. def test_truncate(self):
  92. if verbose:
  93. print('try truncate')
  94. with self.open(TESTFN, 'r+b') as f:
  95. # this is already decided before start running the test suite
  96. # but we do it anyway for extra protection
  97. if not hasattr(f, 'truncate'):
  98. raise unittest.SkipTest("open().truncate() not available on this system")
  99. f.seek(0, 2)
  100. # else we've lost track of the true size
  101. self.assertEqual(f.tell(), size+1)
  102. # Cut it back via seek + truncate with no argument.
  103. newsize = size - 10
  104. f.seek(newsize)
  105. f.truncate()
  106. self.assertEqual(f.tell(), newsize) # else pointer moved
  107. f.seek(0, 2)
  108. self.assertEqual(f.tell(), newsize) # else wasn't truncated
  109. # Ensure that truncate(smaller than true size) shrinks
  110. # the file.
  111. newsize -= 1
  112. f.seek(42)
  113. f.truncate(newsize)
  114. if self.new_io:
  115. self.assertEqual(f.tell(), 42)
  116. f.seek(0, 2)
  117. self.assertEqual(f.tell(), newsize)
  118. # XXX truncate(larger than true size) is ill-defined
  119. # across platform; cut it waaaaay back
  120. f.seek(0)
  121. f.truncate(1)
  122. if self.new_io:
  123. self.assertEqual(f.tell(), 0) # else pointer moved
  124. f.seek(0)
  125. self.assertEqual(len(f.read()), 1) # else wasn't truncated
  126. def test_seekable(self):
  127. # Issue #5016; seekable() can return False when the current position
  128. # is negative when truncated to an int.
  129. if not self.new_io:
  130. self.skipTest("builtin file doesn't have seekable()")
  131. for pos in (2**31-1, 2**31, 2**31+1):
  132. with self.open(TESTFN, 'rb') as f:
  133. f.seek(pos)
  134. self.assertTrue(f.seekable())
  135. def test_main():
  136. # On Windows and Mac OSX this test comsumes large resources; It
  137. # takes a long time to build the >2GB file and takes >2GB of disk
  138. # space therefore the resource must be enabled to run this test.
  139. # If not, nothing after this line stanza will be executed.
  140. if sys.platform[:3] == 'win' or sys.platform == 'darwin':
  141. requires('largefile',
  142. 'test requires %s bytes and a long time to run' % str(size))
  143. else:
  144. # Only run if the current filesystem supports large files.
  145. # (Skip this test on Windows, since we now always support
  146. # large files.)
  147. f = open(TESTFN, 'wb', buffering=0)
  148. try:
  149. # 2**31 == 2147483648
  150. f.seek(2147483649)
  151. # Seeking is not enough of a test: you must write and
  152. # flush, too!
  153. f.write(b'x')
  154. f.flush()
  155. except (IOError, OverflowError):
  156. f.close()
  157. unlink(TESTFN)
  158. raise unittest.SkipTest("filesystem does not have largefile support")
  159. else:
  160. f.close()
  161. suite = unittest.TestSuite()
  162. for _open, prefix in [(io.open, 'C'), (pyio.open, 'Py'),
  163. (open, 'Builtin')]:
  164. class TestCase(LargeFileTest):
  165. pass
  166. TestCase.open = staticmethod(_open)
  167. TestCase.new_io = _open is not open
  168. TestCase.__name__ = prefix + LargeFileTest.__name__
  169. suite.addTest(TestCase('test_seek'))
  170. suite.addTest(TestCase('test_osstat'))
  171. suite.addTest(TestCase('test_seek_read'))
  172. suite.addTest(TestCase('test_lseek'))
  173. with _open(TESTFN, 'wb') as f:
  174. if hasattr(f, 'truncate'):
  175. suite.addTest(TestCase('test_truncate'))
  176. suite.addTest(TestCase('test_seekable'))
  177. unlink(TESTFN)
  178. try:
  179. run_unittest(suite)
  180. finally:
  181. unlink(TESTFN)
  182. if __name__ == '__main__':
  183. test_main()