1 """Test largefile support on system where this makes sense. 2 """ 3 4 import os 5 import stat 6 import sys 7 import unittest 8 from test.support import TESTFN, requires, unlink 9 import io # C implementation of io 10 import _pyio as pyio # Python implementation of io 11 12 # size of file to create (>2GB; 2GB == 2147483648 bytes) 13 size = 2500000000 14 15 class LargeFileTest: 16 """Test that each file function works as expected for large 17 (i.e. > 2GB) files. 18 """ 19 20 def setUp(self): 21 if os.path.exists(TESTFN): 22 mode = 'r+b' 23 else: 24 mode = 'w+b' 25 26 with self.open(TESTFN, mode) as f: 27 current_size = os.fstat(f.fileno())[stat.ST_SIZE] 28 if current_size == size+1: 29 return 30 31 if current_size == 0: 32 f.write(b'z') 33 34 f.seek(0) 35 f.seek(size) 36 f.write(b'a') 37 f.flush() 38 self.assertEqual(os.fstat(f.fileno())[stat.ST_SIZE], size+1) 39 40 @classmethod 41 def tearDownClass(cls): 42 with cls.open(TESTFN, 'wb'): 43 pass 44 if not os.stat(TESTFN)[stat.ST_SIZE] == 0: 45 raise cls.failureException('File was not truncated by opening ' 46 'with mode "wb"') 47 48 def test_osstat(self): 49 self.assertEqual(os.stat(TESTFN)[stat.ST_SIZE], size+1) 50 51 def test_seek_read(self): 52 with self.open(TESTFN, 'rb') as f: 53 self.assertEqual(f.tell(), 0) 54 self.assertEqual(f.read(1), b'z') 55 self.assertEqual(f.tell(), 1) 56 f.seek(0) 57 self.assertEqual(f.tell(), 0) 58 f.seek(0, 0) 59 self.assertEqual(f.tell(), 0) 60 f.seek(42) 61 self.assertEqual(f.tell(), 42) 62 f.seek(42, 0) 63 self.assertEqual(f.tell(), 42) 64 f.seek(42, 1) 65 self.assertEqual(f.tell(), 84) 66 f.seek(0, 1) 67 self.assertEqual(f.tell(), 84) 68 f.seek(0, 2) # seek from the end 69 self.assertEqual(f.tell(), size + 1 + 0) 70 f.seek(-10, 2) 71 self.assertEqual(f.tell(), size + 1 - 10) 72 f.seek(-size-1, 2) 73 self.assertEqual(f.tell(), 0) 74 f.seek(size) 75 self.assertEqual(f.tell(), size) 76 # the 'a' that was written at the end of file above 77 self.assertEqual(f.read(1), b'a') 78 f.seek(-size-1, 1) 79 self.assertEqual(f.read(1), b'z') 80 self.assertEqual(f.tell(), 1) 81 82 def test_lseek(self): 83 with self.open(TESTFN, 'rb') as f: 84 self.assertEqual(os.lseek(f.fileno(), 0, 0), 0) 85 self.assertEqual(os.lseek(f.fileno(), 42, 0), 42) 86 self.assertEqual(os.lseek(f.fileno(), 42, 1), 84) 87 self.assertEqual(os.lseek(f.fileno(), 0, 1), 84) 88 self.assertEqual(os.lseek(f.fileno(), 0, 2), size+1+0) 89 self.assertEqual(os.lseek(f.fileno(), -10, 2), size+1-10) 90 self.assertEqual(os.lseek(f.fileno(), -size-1, 2), 0) 91 self.assertEqual(os.lseek(f.fileno(), size, 0), size) 92 # the 'a' that was written at the end of file above 93 self.assertEqual(f.read(1), b'a') 94 95 def test_truncate(self): 96 with self.open(TESTFN, 'r+b') as f: 97 if not hasattr(f, 'truncate'): 98 raise unittest.SkipTest("open().truncate() not available " 99 "on this system") 100 f.seek(0, 2) 101 # else we've lost track of the true size 102 self.assertEqual(f.tell(), size+1) 103 # Cut it back via seek + truncate with no argument. 104 newsize = size - 10 105 f.seek(newsize) 106 f.truncate() 107 self.assertEqual(f.tell(), newsize) # else pointer moved 108 f.seek(0, 2) 109 self.assertEqual(f.tell(), newsize) # else wasn't truncated 110 # Ensure that truncate(smaller than true size) shrinks 111 # the file. 112 newsize -= 1 113 f.seek(42) 114 f.truncate(newsize) 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 self.assertEqual(f.tell(), 0) # else pointer moved 123 f.seek(0) 124 self.assertEqual(len(f.read()), 1) # else wasn't truncated 125 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 for pos in (2**31-1, 2**31, 2**31+1): 130 with self.open(TESTFN, 'rb') as f: 131 f.seek(pos) 132 self.assertTrue(f.seekable()) 133 134 def setUpModule(): 135 try: 136 import signal 137 # The default handler for SIGXFSZ is to abort the process. 138 # By ignoring it, system calls exceeding the file size resource 139 # limit will raise OSError instead of crashing the interpreter. 140 signal.signal(signal.SIGXFSZ, signal.SIG_IGN) 141 except (ImportError, AttributeError): 142 pass 143 144 # On Windows and Mac OSX this test comsumes large resources; It 145 # takes a long time to build the >2GB file and takes >2GB of disk 146 # space therefore the resource must be enabled to run this test. 147 # If not, nothing after this line stanza will be executed. 148 if sys.platform[:3] == 'win' or sys.platform == 'darwin': 149 requires('largefile', 150 'test requires %s bytes and a long time to run' % str(size)) 151 else: 152 # Only run if the current filesystem supports large files. 153 # (Skip this test on Windows, since we now always support 154 # large files.) 155 f = open(TESTFN, 'wb', buffering=0) 156 try: 157 # 2**31 == 2147483648 158 f.seek(2147483649) 159 # Seeking is not enough of a test: you must write and flush, too! 160 f.write(b'x') 161 f.flush() 162 except (OSError, OverflowError): 163 raise unittest.SkipTest("filesystem does not have " 164 "largefile support") 165 finally: 166 f.close() 167 unlink(TESTFN) 168 169 170 class CLargeFileTest(LargeFileTest, unittest.TestCase): 171 open = staticmethod(io.open) 172 173 class PyLargeFileTest(LargeFileTest, unittest.TestCase): 174 open = staticmethod(pyio.open) 175 176 def tearDownModule(): 177 unlink(TESTFN) 178 179 if __name__ == '__main__': 180 unittest.main() 181