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 test import support 12from collections import UserList 13 14class 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 132class CAutoFileTests(AutoFileTests, unittest.TestCase): 133 open = io.open 134 135class PyAutoFileTests(AutoFileTests, unittest.TestCase): 136 open = staticmethod(pyio.open) 137 138 139class 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 _checkBufferSize(self, s): 173 try: 174 f = self.open(TESTFN, 'wb', s) 175 f.write(str(s).encode("ascii")) 176 f.close() 177 f.close() 178 f = self.open(TESTFN, 'rb', s) 179 d = int(f.read().decode("ascii")) 180 f.close() 181 f.close() 182 except OSError as msg: 183 self.fail('error setting buffer size %d: %s' % (s, str(msg))) 184 self.assertEqual(d, s) 185 186 def testSetBufferSize(self): 187 # make sure that explicitly setting the buffer size doesn't cause 188 # misbehaviour especially with repeated close() calls 189 for s in (-1, 0, 512): 190 with support.check_no_warnings(self, 191 message='line buffering', 192 category=RuntimeWarning): 193 self._checkBufferSize(s) 194 195 # test that attempts to use line buffering in binary mode cause 196 # a warning 197 with self.assertWarnsRegex(RuntimeWarning, 'line buffering'): 198 self._checkBufferSize(1) 199 200 def testTruncateOnWindows(self): 201 # SF bug <http://www.python.org/sf/801631> 202 # "file.truncate fault on windows" 203 204 f = self.open(TESTFN, 'wb') 205 206 try: 207 f.write(b'12345678901') # 11 bytes 208 f.close() 209 210 f = self.open(TESTFN,'rb+') 211 data = f.read(5) 212 if data != b'12345': 213 self.fail("Read on file opened for update failed %r" % data) 214 if f.tell() != 5: 215 self.fail("File pos after read wrong %d" % f.tell()) 216 217 f.truncate() 218 if f.tell() != 5: 219 self.fail("File pos after ftruncate wrong %d" % f.tell()) 220 221 f.close() 222 size = os.path.getsize(TESTFN) 223 if size != 5: 224 self.fail("File size after ftruncate wrong %d" % size) 225 finally: 226 f.close() 227 228 def testIteration(self): 229 # Test the complex interaction when mixing file-iteration and the 230 # various read* methods. 231 dataoffset = 16384 232 filler = b"ham\n" 233 assert not dataoffset % len(filler), \ 234 "dataoffset must be multiple of len(filler)" 235 nchunks = dataoffset // len(filler) 236 testlines = [ 237 b"spam, spam and eggs\n", 238 b"eggs, spam, ham and spam\n", 239 b"saussages, spam, spam and eggs\n", 240 b"spam, ham, spam and eggs\n", 241 b"spam, spam, spam, spam, spam, ham, spam\n", 242 b"wonderful spaaaaaam.\n" 243 ] 244 methods = [("readline", ()), ("read", ()), ("readlines", ()), 245 ("readinto", (array("b", b" "*100),))] 246 247 # Prepare the testfile 248 bag = self.open(TESTFN, "wb") 249 bag.write(filler * nchunks) 250 bag.writelines(testlines) 251 bag.close() 252 # Test for appropriate errors mixing read* and iteration 253 for methodname, args in methods: 254 f = self.open(TESTFN, 'rb') 255 self.assertEqual(next(f), filler) 256 meth = getattr(f, methodname) 257 meth(*args) # This simply shouldn't fail 258 f.close() 259 260 # Test to see if harmless (by accident) mixing of read* and 261 # iteration still works. This depends on the size of the internal 262 # iteration buffer (currently 8192,) but we can test it in a 263 # flexible manner. Each line in the bag o' ham is 4 bytes 264 # ("h", "a", "m", "\n"), so 4096 lines of that should get us 265 # exactly on the buffer boundary for any power-of-2 buffersize 266 # between 4 and 16384 (inclusive). 267 f = self.open(TESTFN, 'rb') 268 for i in range(nchunks): 269 next(f) 270 testline = testlines.pop(0) 271 try: 272 line = f.readline() 273 except ValueError: 274 self.fail("readline() after next() with supposedly empty " 275 "iteration-buffer failed anyway") 276 if line != testline: 277 self.fail("readline() after next() with empty buffer " 278 "failed. Got %r, expected %r" % (line, testline)) 279 testline = testlines.pop(0) 280 buf = array("b", b"\x00" * len(testline)) 281 try: 282 f.readinto(buf) 283 except ValueError: 284 self.fail("readinto() after next() with supposedly empty " 285 "iteration-buffer failed anyway") 286 line = buf.tobytes() 287 if line != testline: 288 self.fail("readinto() after next() with empty buffer " 289 "failed. Got %r, expected %r" % (line, testline)) 290 291 testline = testlines.pop(0) 292 try: 293 line = f.read(len(testline)) 294 except ValueError: 295 self.fail("read() after next() with supposedly empty " 296 "iteration-buffer failed anyway") 297 if line != testline: 298 self.fail("read() after next() with empty buffer " 299 "failed. Got %r, expected %r" % (line, testline)) 300 try: 301 lines = f.readlines() 302 except ValueError: 303 self.fail("readlines() after next() with supposedly empty " 304 "iteration-buffer failed anyway") 305 if lines != testlines: 306 self.fail("readlines() after next() with empty buffer " 307 "failed. Got %r, expected %r" % (line, testline)) 308 f.close() 309 310 # Reading after iteration hit EOF shouldn't hurt either 311 f = self.open(TESTFN, 'rb') 312 try: 313 for line in f: 314 pass 315 try: 316 f.readline() 317 f.readinto(buf) 318 f.read() 319 f.readlines() 320 except ValueError: 321 self.fail("read* failed after next() consumed file") 322 finally: 323 f.close() 324 325class COtherFileTests(OtherFileTests, unittest.TestCase): 326 open = io.open 327 328class PyOtherFileTests(OtherFileTests, unittest.TestCase): 329 open = staticmethod(pyio.open) 330 331 332if __name__ == '__main__': 333 unittest.main() 334