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