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