Home | History | Annotate | Download | only in test
      1 import sys
      2 import os
      3 import unittest
      4 from array import array
      5 from weakref import proxy
      6 
      7 import io
      8 import _pyio as pyio
      9 
     10 from test.support import TESTFN
     11 from test import support
     12 from collections import UserList
     13 
     14 class AutoFileTests:
     15     # file tests for which a test file is automatically set up
     16 
     17     def setUp(self):
     18         self.f = self.open(TESTFN, 'wb')
     19 
     20     def tearDown(self):
     21         if self.f:
     22             self.f.close()
     23         support.unlink(TESTFN)
     24 
     25     def testWeakRefs(self):
     26         # verify weak references
     27         p = proxy(self.f)
     28         p.write(b'teststring')
     29         self.assertEqual(self.f.tell(), p.tell())
     30         self.f.close()
     31         self.f = None
     32         self.assertRaises(ReferenceError, getattr, p, 'tell')
     33 
     34     def testAttributes(self):
     35         # verify expected attributes exist
     36         f = self.f
     37         f.name     # merely shouldn't blow up
     38         f.mode     # ditto
     39         f.closed   # ditto
     40 
     41     def testReadinto(self):
     42         # verify readinto
     43         self.f.write(b'12')
     44         self.f.close()
     45         a = array('b', b'x'*10)
     46         self.f = self.open(TESTFN, 'rb')
     47         n = self.f.readinto(a)
     48         self.assertEqual(b'12', a.tobytes()[:n])
     49 
     50     def testReadinto_text(self):
     51         # verify readinto refuses text files
     52         a = array('b', b'x'*10)
     53         self.f.close()
     54         self.f = self.open(TESTFN, 'r')
     55         if hasattr(self.f, "readinto"):
     56             self.assertRaises(TypeError, self.f.readinto, a)
     57 
     58     def testWritelinesUserList(self):
     59         # verify writelines with instance sequence
     60         l = UserList([b'1', b'2'])
     61         self.f.writelines(l)
     62         self.f.close()
     63         self.f = self.open(TESTFN, 'rb')
     64         buf = self.f.read()
     65         self.assertEqual(buf, b'12')
     66 
     67     def testWritelinesIntegers(self):
     68         # verify writelines with integers
     69         self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
     70 
     71     def testWritelinesIntegersUserList(self):
     72         # verify writelines with integers in UserList
     73         l = UserList([1,2,3])
     74         self.assertRaises(TypeError, self.f.writelines, l)
     75 
     76     def testWritelinesNonString(self):
     77         # verify writelines with non-string object
     78         class NonString:
     79             pass
     80 
     81         self.assertRaises(TypeError, self.f.writelines,
     82                           [NonString(), NonString()])
     83 
     84     def testErrors(self):
     85         f = self.f
     86         self.assertEqual(f.name, TESTFN)
     87         self.assertFalse(f.isatty())
     88         self.assertFalse(f.closed)
     89 
     90         if hasattr(f, "readinto"):
     91             self.assertRaises((OSError, TypeError), f.readinto, "")
     92         f.close()
     93         self.assertTrue(f.closed)
     94 
     95     def testMethods(self):
     96         methods = [('fileno', ()),
     97                    ('flush', ()),
     98                    ('isatty', ()),
     99                    ('__next__', ()),
    100                    ('read', ()),
    101                    ('write', (b"",)),
    102                    ('readline', ()),
    103                    ('readlines', ()),
    104                    ('seek', (0,)),
    105                    ('tell', ()),
    106                    ('write', (b"",)),
    107                    ('writelines', ([],)),
    108                    ('__iter__', ()),
    109                    ]
    110         methods.append(('truncate', ()))
    111 
    112         # __exit__ should close the file
    113         self.f.__exit__(None, None, None)
    114         self.assertTrue(self.f.closed)
    115 
    116         for methodname, args in methods:
    117             method = getattr(self.f, methodname)
    118             # should raise on closed file
    119             self.assertRaises(ValueError, method, *args)
    120 
    121         # file is closed, __exit__ shouldn't do anything
    122         self.assertEqual(self.f.__exit__(None, None, None), None)
    123         # it must also return None if an exception was given
    124         try:
    125             1/0
    126         except:
    127             self.assertEqual(self.f.__exit__(*sys.exc_info()), None)
    128 
    129     def testReadWhenWriting(self):
    130         self.assertRaises(OSError, self.f.read)
    131 
    132 class CAutoFileTests(AutoFileTests, unittest.TestCase):
    133     open = io.open
    134 
    135 class PyAutoFileTests(AutoFileTests, unittest.TestCase):
    136     open = staticmethod(pyio.open)
    137 
    138 
    139 class OtherFileTests:
    140 
    141     def tearDown(self):
    142         support.unlink(TESTFN)
    143 
    144     def testModeStrings(self):
    145         # check invalid mode strings
    146         self.open(TESTFN, 'wb').close()
    147         for mode in ("", "aU", "wU+", "U+", "+U", "rU+"):
    148             try:
    149                 f = self.open(TESTFN, mode)
    150             except ValueError:
    151                 pass
    152             else:
    153                 f.close()
    154                 self.fail('%r is an invalid file mode' % mode)
    155 
    156     def testBadModeArgument(self):
    157         # verify that we get a sensible error message for bad mode argument
    158         bad_mode = "qwerty"
    159         try:
    160             f = self.open(TESTFN, bad_mode)
    161         except ValueError as msg:
    162             if msg.args[0] != 0:
    163                 s = str(msg)
    164                 if TESTFN in s or bad_mode not in s:
    165                     self.fail("bad error message for invalid mode: %s" % s)
    166             # if msg.args[0] == 0, we're probably on Windows where there may be
    167             # no obvious way to discover why open() failed.
    168         else:
    169             f.close()
    170             self.fail("no error for invalid mode: %s" % bad_mode)
    171 
    172     def testSetBufferSize(self):
    173         # make sure that explicitly setting the buffer size doesn't cause
    174         # misbehaviour especially with repeated close() calls
    175         for s in (-1, 0, 1, 512):
    176             try:
    177                 f = self.open(TESTFN, 'wb', s)
    178                 f.write(str(s).encode("ascii"))
    179                 f.close()
    180                 f.close()
    181                 f = self.open(TESTFN, 'rb', s)
    182                 d = int(f.read().decode("ascii"))
    183                 f.close()
    184                 f.close()
    185             except OSError as msg:
    186                 self.fail('error setting buffer size %d: %s' % (s, str(msg)))
    187             self.assertEqual(d, s)
    188 
    189     def testTruncateOnWindows(self):
    190         # SF bug <http://www.python.org/sf/801631>
    191         # "file.truncate fault on windows"
    192 
    193         f = self.open(TESTFN, 'wb')
    194 
    195         try:
    196             f.write(b'12345678901')   # 11 bytes
    197             f.close()
    198 
    199             f = self.open(TESTFN,'rb+')
    200             data = f.read(5)
    201             if data != b'12345':
    202                 self.fail("Read on file opened for update failed %r" % data)
    203             if f.tell() != 5:
    204                 self.fail("File pos after read wrong %d" % f.tell())
    205 
    206             f.truncate()
    207             if f.tell() != 5:
    208                 self.fail("File pos after ftruncate wrong %d" % f.tell())
    209 
    210             f.close()
    211             size = os.path.getsize(TESTFN)
    212             if size != 5:
    213                 self.fail("File size after ftruncate wrong %d" % size)
    214         finally:
    215             f.close()
    216 
    217     def testIteration(self):
    218         # Test the complex interaction when mixing file-iteration and the
    219         # various read* methods.
    220         dataoffset = 16384
    221         filler = b"ham\n"
    222         assert not dataoffset % len(filler), \
    223             "dataoffset must be multiple of len(filler)"
    224         nchunks = dataoffset // len(filler)
    225         testlines = [
    226             b"spam, spam and eggs\n",
    227             b"eggs, spam, ham and spam\n",
    228             b"saussages, spam, spam and eggs\n",
    229             b"spam, ham, spam and eggs\n",
    230             b"spam, spam, spam, spam, spam, ham, spam\n",
    231             b"wonderful spaaaaaam.\n"
    232         ]
    233         methods = [("readline", ()), ("read", ()), ("readlines", ()),
    234                    ("readinto", (array("b", b" "*100),))]
    235 
    236         # Prepare the testfile
    237         bag = self.open(TESTFN, "wb")
    238         bag.write(filler * nchunks)
    239         bag.writelines(testlines)
    240         bag.close()
    241         # Test for appropriate errors mixing read* and iteration
    242         for methodname, args in methods:
    243             f = self.open(TESTFN, 'rb')
    244             self.assertEqual(next(f), filler)
    245             meth = getattr(f, methodname)
    246             meth(*args)  # This simply shouldn't fail
    247             f.close()
    248 
    249         # Test to see if harmless (by accident) mixing of read* and
    250         # iteration still works. This depends on the size of the internal
    251         # iteration buffer (currently 8192,) but we can test it in a
    252         # flexible manner.  Each line in the bag o' ham is 4 bytes
    253         # ("h", "a", "m", "\n"), so 4096 lines of that should get us
    254         # exactly on the buffer boundary for any power-of-2 buffersize
    255         # between 4 and 16384 (inclusive).
    256         f = self.open(TESTFN, 'rb')
    257         for i in range(nchunks):
    258             next(f)
    259         testline = testlines.pop(0)
    260         try:
    261             line = f.readline()
    262         except ValueError:
    263             self.fail("readline() after next() with supposedly empty "
    264                         "iteration-buffer failed anyway")
    265         if line != testline:
    266             self.fail("readline() after next() with empty buffer "
    267                         "failed. Got %r, expected %r" % (line, testline))
    268         testline = testlines.pop(0)
    269         buf = array("b", b"\x00" * len(testline))
    270         try:
    271             f.readinto(buf)
    272         except ValueError:
    273             self.fail("readinto() after next() with supposedly empty "
    274                         "iteration-buffer failed anyway")
    275         line = buf.tobytes()
    276         if line != testline:
    277             self.fail("readinto() after next() with empty buffer "
    278                         "failed. Got %r, expected %r" % (line, testline))
    279 
    280         testline = testlines.pop(0)
    281         try:
    282             line = f.read(len(testline))
    283         except ValueError:
    284             self.fail("read() after next() with supposedly empty "
    285                         "iteration-buffer failed anyway")
    286         if line != testline:
    287             self.fail("read() after next() with empty buffer "
    288                         "failed. Got %r, expected %r" % (line, testline))
    289         try:
    290             lines = f.readlines()
    291         except ValueError:
    292             self.fail("readlines() after next() with supposedly empty "
    293                         "iteration-buffer failed anyway")
    294         if lines != testlines:
    295             self.fail("readlines() after next() with empty buffer "
    296                         "failed. Got %r, expected %r" % (line, testline))
    297         f.close()
    298 
    299         # Reading after iteration hit EOF shouldn't hurt either
    300         f = self.open(TESTFN, 'rb')
    301         try:
    302             for line in f:
    303                 pass
    304             try:
    305                 f.readline()
    306                 f.readinto(buf)
    307                 f.read()
    308                 f.readlines()
    309             except ValueError:
    310                 self.fail("read* failed after next() consumed file")
    311         finally:
    312             f.close()
    313 
    314 class COtherFileTests(OtherFileTests, unittest.TestCase):
    315     open = io.open
    316 
    317 class PyOtherFileTests(OtherFileTests, unittest.TestCase):
    318     open = staticmethod(pyio.open)
    319 
    320 
    321 if __name__ == '__main__':
    322     unittest.main()
    323