1import sys 2import os 3import unittest 4from array import array 5from weakref import proxy 6 7import io 8import _pyio as pyio 9 10from test.support import TESTFN 11from collections import UserList 12 13class 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 131class CAutoFileTests(AutoFileTests, unittest.TestCase): 132 open = io.open 133 134class PyAutoFileTests(AutoFileTests, unittest.TestCase): 135 open = staticmethod(pyio.open) 136 137 138class 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 315class COtherFileTests(OtherFileTests, unittest.TestCase): 316 open = io.open 317 318class PyOtherFileTests(OtherFileTests, unittest.TestCase): 319 open = staticmethod(pyio.open) 320 321 322def 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 328if __name__ == '__main__': 329 unittest.main() 330