test_largefile.py 6.47 KB
Newer Older
1 2
"""Test largefile support on system where this makes sense.
"""
3

4 5 6 7 8 9
import os
import stat
import sys
import unittest
from test.test_support import run_unittest, TESTFN, verbose, requires, \
                              TestSkipped, unlink
10

11 12 13 14 15 16 17 18 19
try:
    import signal
    # The default handler for SIGXFSZ is to abort the process.
    # By ignoring it, system calls exceeding the file size resource
    # limit will raise IOError instead of crashing the interpreter.
    oldhandler = signal.signal(signal.SIGXFSZ, signal.SIG_IGN)
except (ImportError, AttributeError):
    pass

20 21
# create >2GB file (2GB = 2147483648 bytes)
size = 2500000000L
22 23


24 25 26
class TestCase(unittest.TestCase):
    """Test that each file function works as expected for a large
    (i.e. > 2GB, do  we have to check > 4GB) files.
27

28 29 30 31
    NOTE: the order of execution of the test methods is important! test_seek
    must run first to create the test file. File cleanup must also be handled
    outside the test instances because of this.

32 33 34 35 36
    """

    def test_seek(self):
        if verbose:
            print 'create large file via seek (may be sparse file) ...'
37
        with open(TESTFN, 'wb') as f:
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
            f.write('z')
            f.seek(0)
            f.seek(size)
            f.write('a')
            f.flush()
            if verbose:
                print 'check file size with os.fstat'
            self.assertEqual(os.fstat(f.fileno())[stat.ST_SIZE], size+1)

    def test_osstat(self):
        if verbose:
            print 'check file size with os.stat'
        self.assertEqual(os.stat(TESTFN)[stat.ST_SIZE], size+1)

    def test_seek_read(self):
        if verbose:
            print 'play around with seek() and read() with the built largefile'
55
        with open(TESTFN, 'rb') as f:
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
            self.assertEqual(f.tell(), 0)
            self.assertEqual(f.read(1), 'z')
            self.assertEqual(f.tell(), 1)
            f.seek(0)
            self.assertEqual(f.tell(), 0)
            f.seek(0, 0)
            self.assertEqual(f.tell(), 0)
            f.seek(42)
            self.assertEqual(f.tell(), 42)
            f.seek(42, 0)
            self.assertEqual(f.tell(), 42)
            f.seek(42, 1)
            self.assertEqual(f.tell(), 84)
            f.seek(0, 1)
            self.assertEqual(f.tell(), 84)
            f.seek(0, 2)  # seek from the end
            self.assertEqual(f.tell(), size + 1 + 0)
            f.seek(-10, 2)
            self.assertEqual(f.tell(), size + 1 - 10)
            f.seek(-size-1, 2)
            self.assertEqual(f.tell(), 0)
            f.seek(size)
            self.assertEqual(f.tell(), size)
            # the 'a' that was written at the end of file above
            self.assertEqual(f.read(1), 'a')
            f.seek(-size-1, 1)
            self.assertEqual(f.read(1), 'z')
            self.assertEqual(f.tell(), 1)

    def test_lseek(self):
        if verbose:
            print 'play around with os.lseek() with the built largefile'
88
        with open(TESTFN, 'rb') as f:
89 90 91 92 93 94 95 96 97 98 99 100 101 102
            self.assertEqual(os.lseek(f.fileno(), 0, 0), 0)
            self.assertEqual(os.lseek(f.fileno(), 42, 0), 42)
            self.assertEqual(os.lseek(f.fileno(), 42, 1), 84)
            self.assertEqual(os.lseek(f.fileno(), 0, 1), 84)
            self.assertEqual(os.lseek(f.fileno(), 0, 2), size+1+0)
            self.assertEqual(os.lseek(f.fileno(), -10, 2), size+1-10)
            self.assertEqual(os.lseek(f.fileno(), -size-1, 2), 0)
            self.assertEqual(os.lseek(f.fileno(), size, 0), size)
            # the 'a' that was written at the end of file above
            self.assertEqual(f.read(1), 'a')

    def test_truncate(self):
        if verbose:
            print 'try truncate'
103 104 105 106 107
        with open(TESTFN, 'r+b') as f:
            # this is already decided before start running the test suite
            # but we do it anyway for extra protection
            if not hasattr(f, 'truncate'):
                raise TestSkipped, "open().truncate() not available on this system"
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
            f.seek(0, 2)
            # else we've lost track of the true size
            self.assertEqual(f.tell(), size+1)
            # Cut it back via seek + truncate with no argument.
            newsize = size - 10
            f.seek(newsize)
            f.truncate()
            self.assertEqual(f.tell(), newsize)  # else pointer moved
            f.seek(0, 2)
            self.assertEqual(f.tell(), newsize)  # else wasn't truncated
            # Ensure that truncate(smaller than true size) shrinks
            # the file.
            newsize -= 1
            f.seek(42)
            f.truncate(newsize)
            self.assertEqual(f.tell(), 42)       # else pointer moved
            f.seek(0, 2)
            self.assertEqual(f.tell(), newsize)  # else wasn't truncated

            # XXX truncate(larger than true size) is ill-defined
            # across platform; cut it waaaaay back
            f.seek(0)
            f.truncate(1)
            self.assertEqual(f.tell(), 0)       # else pointer moved
            self.assertEqual(len(f.read()), 1)  # else wasn't truncated


135
def test_main():
136 137 138 139 140 141 142
    # On Windows and Mac OSX this test comsumes large resources; It
    # takes a long time to build the >2GB file and takes >2GB of disk
    # space therefore the resource must be enabled to run this test.
    # If not, nothing after this line stanza will be executed.
    if sys.platform[:3] == 'win' or sys.platform == 'darwin':
        requires('largefile',
                 'test requires %s bytes and a long time to run' % str(size))
143
    else:
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
        # Only run if the current filesystem supports large files.
        # (Skip this test on Windows, since we now always support
        # large files.)
        f = open(TESTFN, 'wb')
        try:
            # 2**31 == 2147483648
            f.seek(2147483649L)
            # Seeking is not enough of a test: you must write and
            # flush, too!
            f.write("x")
            f.flush()
        except (IOError, OverflowError):
            f.close()
            unlink(TESTFN)
            raise TestSkipped, "filesystem does not have largefile support"
        else:
            f.close()
    suite = unittest.TestSuite()
    suite.addTest(TestCase('test_seek'))
    suite.addTest(TestCase('test_osstat'))
    suite.addTest(TestCase('test_seek_read'))
    suite.addTest(TestCase('test_lseek'))
166 167 168
    with open(TESTFN, 'w') as f:
        if hasattr(f, 'truncate'):
            suite.addTest(TestCase('test_truncate'))
169
    unlink(TESTFN)
170 171 172 173
    try:
        run_unittest(suite)
    finally:
        unlink(TESTFN)
174

175

176
if __name__ == '__main__':
177
    test_main()