blob: 16da8d8f174738e90dedcc721139db27394ba5d7 [file] [log] [blame]
Facundo Batista9521f082008-02-07 16:16:29 +00001"""Test largefile support on system where this makes sense.
2"""
Trent Mickf29f47b2000-08-11 19:02:59 +00003
Antoine Pitrou19690592009-06-12 20:14:08 +00004from __future__ import print_function
5
Facundo Batista9521f082008-02-07 16:16:29 +00006import os
7import stat
8import sys
9import unittest
10from test.test_support import run_unittest, TESTFN, verbose, requires, \
Benjamin Petersonbec087f2009-03-26 21:10:30 +000011 unlink
Antoine Pitrou19690592009-06-12 20:14:08 +000012import io # C implementation of io
13import _pyio as pyio # Python implementation of io
Trent Mickf29f47b2000-08-11 19:02:59 +000014
Martin v. Löwisdf8adcd2001-12-11 17:57:26 +000015try:
16 import signal
17 # The default handler for SIGXFSZ is to abort the process.
18 # By ignoring it, system calls exceeding the file size resource
19 # limit will raise IOError instead of crashing the interpreter.
20 oldhandler = signal.signal(signal.SIGXFSZ, signal.SIG_IGN)
21except (ImportError, AttributeError):
22 pass
23
Guido van Rossuma31ddbb2001-09-10 15:03:18 +000024# create >2GB file (2GB = 2147483648 bytes)
Antoine Pitrou19690592009-06-12 20:14:08 +000025size = 2500000000
Guido van Rossuma31ddbb2001-09-10 15:03:18 +000026
27
Antoine Pitrou19690592009-06-12 20:14:08 +000028class LargeFileTest(unittest.TestCase):
Facundo Batista9521f082008-02-07 16:16:29 +000029 """Test that each file function works as expected for a large
30 (i.e. > 2GB, do we have to check > 4GB) files.
Brett Cannon6382ffc2008-03-03 02:41:40 +000031
Brett Cannonbfbf5b32008-03-03 03:24:48 +000032 NOTE: the order of execution of the test methods is important! test_seek
33 must run first to create the test file. File cleanup must also be handled
34 outside the test instances because of this.
35
Facundo Batista9521f082008-02-07 16:16:29 +000036 """
37
38 def test_seek(self):
39 if verbose:
Antoine Pitrou19690592009-06-12 20:14:08 +000040 print('create large file via seek (may be sparse file) ...')
41 with self.open(TESTFN, 'wb') as f:
42 f.write(b'z')
Facundo Batista9521f082008-02-07 16:16:29 +000043 f.seek(0)
44 f.seek(size)
Antoine Pitrou19690592009-06-12 20:14:08 +000045 f.write(b'a')
Facundo Batista9521f082008-02-07 16:16:29 +000046 f.flush()
47 if verbose:
Antoine Pitrou19690592009-06-12 20:14:08 +000048 print('check file size with os.fstat')
Facundo Batista9521f082008-02-07 16:16:29 +000049 self.assertEqual(os.fstat(f.fileno())[stat.ST_SIZE], size+1)
Facundo Batista9521f082008-02-07 16:16:29 +000050
51 def test_osstat(self):
52 if verbose:
Antoine Pitrou19690592009-06-12 20:14:08 +000053 print('check file size with os.stat')
Facundo Batista9521f082008-02-07 16:16:29 +000054 self.assertEqual(os.stat(TESTFN)[stat.ST_SIZE], size+1)
55
56 def test_seek_read(self):
57 if verbose:
Antoine Pitrou19690592009-06-12 20:14:08 +000058 print('play around with seek() and read() with the built largefile')
59 with self.open(TESTFN, 'rb') as f:
Facundo Batista9521f082008-02-07 16:16:29 +000060 self.assertEqual(f.tell(), 0)
Antoine Pitrou19690592009-06-12 20:14:08 +000061 self.assertEqual(f.read(1), b'z')
Facundo Batista9521f082008-02-07 16:16:29 +000062 self.assertEqual(f.tell(), 1)
63 f.seek(0)
64 self.assertEqual(f.tell(), 0)
65 f.seek(0, 0)
66 self.assertEqual(f.tell(), 0)
67 f.seek(42)
68 self.assertEqual(f.tell(), 42)
69 f.seek(42, 0)
70 self.assertEqual(f.tell(), 42)
71 f.seek(42, 1)
72 self.assertEqual(f.tell(), 84)
73 f.seek(0, 1)
74 self.assertEqual(f.tell(), 84)
75 f.seek(0, 2) # seek from the end
76 self.assertEqual(f.tell(), size + 1 + 0)
77 f.seek(-10, 2)
78 self.assertEqual(f.tell(), size + 1 - 10)
79 f.seek(-size-1, 2)
80 self.assertEqual(f.tell(), 0)
81 f.seek(size)
82 self.assertEqual(f.tell(), size)
83 # the 'a' that was written at the end of file above
Antoine Pitrou19690592009-06-12 20:14:08 +000084 self.assertEqual(f.read(1), b'a')
Facundo Batista9521f082008-02-07 16:16:29 +000085 f.seek(-size-1, 1)
Antoine Pitrou19690592009-06-12 20:14:08 +000086 self.assertEqual(f.read(1), b'z')
Facundo Batista9521f082008-02-07 16:16:29 +000087 self.assertEqual(f.tell(), 1)
Facundo Batista9521f082008-02-07 16:16:29 +000088
89 def test_lseek(self):
90 if verbose:
Antoine Pitrou19690592009-06-12 20:14:08 +000091 print('play around with os.lseek() with the built largefile')
92 with self.open(TESTFN, 'rb') as f:
Facundo Batista9521f082008-02-07 16:16:29 +000093 self.assertEqual(os.lseek(f.fileno(), 0, 0), 0)
94 self.assertEqual(os.lseek(f.fileno(), 42, 0), 42)
95 self.assertEqual(os.lseek(f.fileno(), 42, 1), 84)
96 self.assertEqual(os.lseek(f.fileno(), 0, 1), 84)
97 self.assertEqual(os.lseek(f.fileno(), 0, 2), size+1+0)
98 self.assertEqual(os.lseek(f.fileno(), -10, 2), size+1-10)
99 self.assertEqual(os.lseek(f.fileno(), -size-1, 2), 0)
100 self.assertEqual(os.lseek(f.fileno(), size, 0), size)
101 # the 'a' that was written at the end of file above
Antoine Pitrou19690592009-06-12 20:14:08 +0000102 self.assertEqual(f.read(1), b'a')
Facundo Batista9521f082008-02-07 16:16:29 +0000103
104 def test_truncate(self):
105 if verbose:
Antoine Pitrou19690592009-06-12 20:14:08 +0000106 print('try truncate')
107 with self.open(TESTFN, 'r+b') as f:
Brett Cannon6382ffc2008-03-03 02:41:40 +0000108 # this is already decided before start running the test suite
109 # but we do it anyway for extra protection
110 if not hasattr(f, 'truncate'):
Antoine Pitrou19690592009-06-12 20:14:08 +0000111 raise unittest.SkipTest("open().truncate() not available on this system")
Facundo Batista9521f082008-02-07 16:16:29 +0000112 f.seek(0, 2)
113 # else we've lost track of the true size
114 self.assertEqual(f.tell(), size+1)
115 # Cut it back via seek + truncate with no argument.
116 newsize = size - 10
117 f.seek(newsize)
118 f.truncate()
119 self.assertEqual(f.tell(), newsize) # else pointer moved
120 f.seek(0, 2)
121 self.assertEqual(f.tell(), newsize) # else wasn't truncated
122 # Ensure that truncate(smaller than true size) shrinks
123 # the file.
124 newsize -= 1
125 f.seek(42)
126 f.truncate(newsize)
Antoine Pitrouc5ae86b2009-06-12 20:54:21 +0000127 if self.new_io:
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000128 self.assertEqual(f.tell(), 42)
Antoine Pitrou19690592009-06-12 20:14:08 +0000129 f.seek(0, 2)
130 self.assertEqual(f.tell(), newsize)
Facundo Batista9521f082008-02-07 16:16:29 +0000131 # XXX truncate(larger than true size) is ill-defined
132 # across platform; cut it waaaaay back
133 f.seek(0)
134 f.truncate(1)
Antoine Pitrouc5ae86b2009-06-12 20:54:21 +0000135 if self.new_io:
Antoine Pitrouf3fa0742010-01-31 22:26:04 +0000136 self.assertEqual(f.tell(), 0) # else pointer moved
Antoine Pitrou19690592009-06-12 20:14:08 +0000137 f.seek(0)
Facundo Batista9521f082008-02-07 16:16:29 +0000138 self.assertEqual(len(f.read()), 1) # else wasn't truncated
Facundo Batista9521f082008-02-07 16:16:29 +0000139
Antoine Pitrou19690592009-06-12 20:14:08 +0000140 def test_seekable(self):
141 # Issue #5016; seekable() can return False when the current position
142 # is negative when truncated to an int.
Antoine Pitrouc5ae86b2009-06-12 20:54:21 +0000143 if not self.new_io:
144 self.skipTest("builtin file doesn't have seekable()")
Antoine Pitrou19690592009-06-12 20:14:08 +0000145 for pos in (2**31-1, 2**31, 2**31+1):
146 with self.open(TESTFN, 'rb') as f:
147 f.seek(pos)
Benjamin Peterson5c8da862009-06-30 22:57:08 +0000148 self.assertTrue(f.seekable())
Antoine Pitrou19690592009-06-12 20:14:08 +0000149
Facundo Batista9521f082008-02-07 16:16:29 +0000150
Brett Cannon6382ffc2008-03-03 02:41:40 +0000151def test_main():
Facundo Batista9521f082008-02-07 16:16:29 +0000152 # On Windows and Mac OSX this test comsumes large resources; It
153 # takes a long time to build the >2GB file and takes >2GB of disk
154 # space therefore the resource must be enabled to run this test.
155 # If not, nothing after this line stanza will be executed.
156 if sys.platform[:3] == 'win' or sys.platform == 'darwin':
157 requires('largefile',
158 'test requires %s bytes and a long time to run' % str(size))
Guido van Rossum47f40342001-09-10 13:34:12 +0000159 else:
Facundo Batista9521f082008-02-07 16:16:29 +0000160 # Only run if the current filesystem supports large files.
161 # (Skip this test on Windows, since we now always support
162 # large files.)
Antoine Pitrou19690592009-06-12 20:14:08 +0000163 f = open(TESTFN, 'wb', buffering=0)
Facundo Batista9521f082008-02-07 16:16:29 +0000164 try:
165 # 2**31 == 2147483648
Antoine Pitrou19690592009-06-12 20:14:08 +0000166 f.seek(2147483649)
Facundo Batista9521f082008-02-07 16:16:29 +0000167 # Seeking is not enough of a test: you must write and
168 # flush, too!
Antoine Pitrou19690592009-06-12 20:14:08 +0000169 f.write(b'x')
Facundo Batista9521f082008-02-07 16:16:29 +0000170 f.flush()
171 except (IOError, OverflowError):
172 f.close()
173 unlink(TESTFN)
Antoine Pitrou19690592009-06-12 20:14:08 +0000174 raise unittest.SkipTest("filesystem does not have largefile support")
Facundo Batista9521f082008-02-07 16:16:29 +0000175 else:
176 f.close()
177 suite = unittest.TestSuite()
Antoine Pitrouc5ae86b2009-06-12 20:54:21 +0000178 for _open, prefix in [(io.open, 'C'), (pyio.open, 'Py'),
179 (open, 'Builtin')]:
Antoine Pitrou19690592009-06-12 20:14:08 +0000180 class TestCase(LargeFileTest):
181 pass
182 TestCase.open = staticmethod(_open)
Antoine Pitrouc5ae86b2009-06-12 20:54:21 +0000183 TestCase.new_io = _open is not open
Antoine Pitrou19690592009-06-12 20:14:08 +0000184 TestCase.__name__ = prefix + LargeFileTest.__name__
185 suite.addTest(TestCase('test_seek'))
186 suite.addTest(TestCase('test_osstat'))
187 suite.addTest(TestCase('test_seek_read'))
188 suite.addTest(TestCase('test_lseek'))
189 with _open(TESTFN, 'wb') as f:
190 if hasattr(f, 'truncate'):
191 suite.addTest(TestCase('test_truncate'))
192 suite.addTest(TestCase('test_seekable'))
193 unlink(TESTFN)
Brett Cannon6382ffc2008-03-03 02:41:40 +0000194 try:
195 run_unittest(suite)
196 finally:
197 unlink(TESTFN)
Trent Mickf29f47b2000-08-11 19:02:59 +0000198
Facundo Batista9521f082008-02-07 16:16:29 +0000199if __name__ == '__main__':
Brett Cannon6382ffc2008-03-03 02:41:40 +0000200 test_main()