| 1 | import sys
|
|---|
| 2 | import os
|
|---|
| 3 | import unittest
|
|---|
| 4 | from array import array
|
|---|
| 5 | from weakref import proxy
|
|---|
| 6 |
|
|---|
| 7 | from test.test_support import TESTFN, findfile, run_unittest
|
|---|
| 8 | from UserList import UserList
|
|---|
| 9 |
|
|---|
| 10 | class AutoFileTests(unittest.TestCase):
|
|---|
| 11 | # file tests for which a test file is automatically set up
|
|---|
| 12 |
|
|---|
| 13 | def setUp(self):
|
|---|
| 14 | self.f = open(TESTFN, 'wb')
|
|---|
| 15 |
|
|---|
| 16 | def tearDown(self):
|
|---|
| 17 | if self.f:
|
|---|
| 18 | self.f.close()
|
|---|
| 19 | os.remove(TESTFN)
|
|---|
| 20 |
|
|---|
| 21 | def testWeakRefs(self):
|
|---|
| 22 | # verify weak references
|
|---|
| 23 | p = proxy(self.f)
|
|---|
| 24 | p.write('teststring')
|
|---|
| 25 | self.assertEquals(self.f.tell(), p.tell())
|
|---|
| 26 | self.f.close()
|
|---|
| 27 | self.f = None
|
|---|
| 28 | self.assertRaises(ReferenceError, getattr, p, 'tell')
|
|---|
| 29 |
|
|---|
| 30 | def testAttributes(self):
|
|---|
| 31 | # verify expected attributes exist
|
|---|
| 32 | f = self.f
|
|---|
| 33 | softspace = f.softspace
|
|---|
| 34 | f.name # merely shouldn't blow up
|
|---|
| 35 | f.mode # ditto
|
|---|
| 36 | f.closed # ditto
|
|---|
| 37 |
|
|---|
| 38 | # verify softspace is writable
|
|---|
| 39 | f.softspace = softspace # merely shouldn't blow up
|
|---|
| 40 |
|
|---|
| 41 | # verify the others aren't
|
|---|
| 42 | for attr in 'name', 'mode', 'closed':
|
|---|
| 43 | self.assertRaises((AttributeError, TypeError), setattr, f, attr, 'oops')
|
|---|
| 44 |
|
|---|
| 45 | def testReadinto(self):
|
|---|
| 46 | # verify readinto
|
|---|
| 47 | self.f.write('12')
|
|---|
| 48 | self.f.close()
|
|---|
| 49 | a = array('c', 'x'*10)
|
|---|
| 50 | self.f = open(TESTFN, 'rb')
|
|---|
| 51 | n = self.f.readinto(a)
|
|---|
| 52 | self.assertEquals('12', a.tostring()[:n])
|
|---|
| 53 |
|
|---|
| 54 | def testWritelinesUserList(self):
|
|---|
| 55 | # verify writelines with instance sequence
|
|---|
| 56 | l = UserList(['1', '2'])
|
|---|
| 57 | self.f.writelines(l)
|
|---|
| 58 | self.f.close()
|
|---|
| 59 | self.f = open(TESTFN, 'rb')
|
|---|
| 60 | buf = self.f.read()
|
|---|
| 61 | self.assertEquals(buf, '12')
|
|---|
| 62 |
|
|---|
| 63 | def testWritelinesIntegers(self):
|
|---|
| 64 | # verify writelines with integers
|
|---|
| 65 | self.assertRaises(TypeError, self.f.writelines, [1, 2, 3])
|
|---|
| 66 |
|
|---|
| 67 | def testWritelinesIntegersUserList(self):
|
|---|
| 68 | # verify writelines with integers in UserList
|
|---|
| 69 | l = UserList([1,2,3])
|
|---|
| 70 | self.assertRaises(TypeError, self.f.writelines, l)
|
|---|
| 71 |
|
|---|
| 72 | def testWritelinesNonString(self):
|
|---|
| 73 | # verify writelines with non-string object
|
|---|
| 74 | class NonString:
|
|---|
| 75 | pass
|
|---|
| 76 |
|
|---|
| 77 | self.assertRaises(TypeError, self.f.writelines,
|
|---|
| 78 | [NonString(), NonString()])
|
|---|
| 79 |
|
|---|
| 80 | def testRepr(self):
|
|---|
| 81 | # verify repr works
|
|---|
| 82 | self.assert_(repr(self.f).startswith("<open file '" + TESTFN))
|
|---|
| 83 |
|
|---|
| 84 | def testErrors(self):
|
|---|
| 85 | f = self.f
|
|---|
| 86 | self.assertEquals(f.name, TESTFN)
|
|---|
| 87 | self.assert_(not f.isatty())
|
|---|
| 88 | self.assert_(not f.closed)
|
|---|
| 89 |
|
|---|
| 90 | self.assertRaises(TypeError, f.readinto, "")
|
|---|
| 91 | f.close()
|
|---|
| 92 | self.assert_(f.closed)
|
|---|
| 93 |
|
|---|
| 94 | def testMethods(self):
|
|---|
| 95 | methods = ['fileno', 'flush', 'isatty', 'next', 'read', 'readinto',
|
|---|
| 96 | 'readline', 'readlines', 'seek', 'tell', 'truncate',
|
|---|
| 97 | 'write', 'xreadlines', '__iter__']
|
|---|
| 98 | if sys.platform.startswith('atheos'):
|
|---|
| 99 | methods.remove('truncate')
|
|---|
| 100 |
|
|---|
| 101 | # __exit__ should close the file
|
|---|
| 102 | self.f.__exit__(None, None, None)
|
|---|
| 103 | self.assert_(self.f.closed)
|
|---|
| 104 |
|
|---|
| 105 | for methodname in methods:
|
|---|
| 106 | method = getattr(self.f, methodname)
|
|---|
| 107 | # should raise on closed file
|
|---|
| 108 | self.assertRaises(ValueError, method)
|
|---|
| 109 | self.assertRaises(ValueError, self.f.writelines, [])
|
|---|
| 110 |
|
|---|
| 111 | # file is closed, __exit__ shouldn't do anything
|
|---|
| 112 | self.assertEquals(self.f.__exit__(None, None, None), None)
|
|---|
| 113 | # it must also return None if an exception was given
|
|---|
| 114 | try:
|
|---|
| 115 | 1/0
|
|---|
| 116 | except:
|
|---|
| 117 | self.assertEquals(self.f.__exit__(*sys.exc_info()), None)
|
|---|
| 118 |
|
|---|
| 119 |
|
|---|
| 120 | class OtherFileTests(unittest.TestCase):
|
|---|
| 121 |
|
|---|
| 122 | def testModeStrings(self):
|
|---|
| 123 | # check invalid mode strings
|
|---|
| 124 | for mode in ("", "aU", "wU+"):
|
|---|
| 125 | try:
|
|---|
| 126 | f = open(TESTFN, mode)
|
|---|
| 127 | except ValueError:
|
|---|
| 128 | pass
|
|---|
| 129 | else:
|
|---|
| 130 | f.close()
|
|---|
| 131 | self.fail('%r is an invalid file mode' % mode)
|
|---|
| 132 |
|
|---|
| 133 | def testStdin(self):
|
|---|
| 134 | # This causes the interpreter to exit on OSF1 v5.1.
|
|---|
| 135 | if sys.platform != 'osf1V5':
|
|---|
| 136 | self.assertRaises(IOError, sys.stdin.seek, -1)
|
|---|
| 137 | else:
|
|---|
| 138 | print >>sys.__stdout__, (
|
|---|
| 139 | ' Skipping sys.stdin.seek(-1), it may crash the interpreter.'
|
|---|
| 140 | ' Test manually.')
|
|---|
| 141 | self.assertRaises(IOError, sys.stdin.truncate)
|
|---|
| 142 |
|
|---|
| 143 | def testUnicodeOpen(self):
|
|---|
| 144 | # verify repr works for unicode too
|
|---|
| 145 | f = open(unicode(TESTFN), "w")
|
|---|
| 146 | self.assert_(repr(f).startswith("<open file u'" + TESTFN))
|
|---|
| 147 | f.close()
|
|---|
| 148 | os.unlink(TESTFN)
|
|---|
| 149 |
|
|---|
| 150 | def testBadModeArgument(self):
|
|---|
| 151 | # verify that we get a sensible error message for bad mode argument
|
|---|
| 152 | bad_mode = "qwerty"
|
|---|
| 153 | try:
|
|---|
| 154 | f = open(TESTFN, bad_mode)
|
|---|
| 155 | except ValueError, msg:
|
|---|
| 156 | if msg[0] != 0:
|
|---|
| 157 | s = str(msg)
|
|---|
| 158 | if s.find(TESTFN) != -1 or s.find(bad_mode) == -1:
|
|---|
| 159 | self.fail("bad error message for invalid mode: %s" % s)
|
|---|
| 160 | # if msg[0] == 0, we're probably on Windows where there may be
|
|---|
| 161 | # no obvious way to discover why open() failed.
|
|---|
| 162 | else:
|
|---|
| 163 | f.close()
|
|---|
| 164 | self.fail("no error for invalid mode: %s" % bad_mode)
|
|---|
| 165 |
|
|---|
| 166 | def testSetBufferSize(self):
|
|---|
| 167 | # make sure that explicitly setting the buffer size doesn't cause
|
|---|
| 168 | # misbehaviour especially with repeated close() calls
|
|---|
| 169 | for s in (-1, 0, 1, 512):
|
|---|
| 170 | try:
|
|---|
| 171 | f = open(TESTFN, 'w', s)
|
|---|
| 172 | f.write(str(s))
|
|---|
| 173 | f.close()
|
|---|
| 174 | f.close()
|
|---|
| 175 | f = open(TESTFN, 'r', s)
|
|---|
| 176 | d = int(f.read())
|
|---|
| 177 | f.close()
|
|---|
| 178 | f.close()
|
|---|
| 179 | except IOError, msg:
|
|---|
| 180 | self.fail('error setting buffer size %d: %s' % (s, str(msg)))
|
|---|
| 181 | self.assertEquals(d, s)
|
|---|
| 182 |
|
|---|
| 183 | def testTruncateOnWindows(self):
|
|---|
| 184 | os.unlink(TESTFN)
|
|---|
| 185 |
|
|---|
| 186 | def bug801631():
|
|---|
| 187 | # SF bug <http://www.python.org/sf/801631>
|
|---|
| 188 | # "file.truncate fault on windows"
|
|---|
| 189 | f = open(TESTFN, 'wb')
|
|---|
| 190 | f.write('12345678901') # 11 bytes
|
|---|
| 191 | f.close()
|
|---|
| 192 |
|
|---|
| 193 | f = open(TESTFN,'rb+')
|
|---|
| 194 | data = f.read(5)
|
|---|
| 195 | if data != '12345':
|
|---|
| 196 | self.fail("Read on file opened for update failed %r" % data)
|
|---|
| 197 | if f.tell() != 5:
|
|---|
| 198 | self.fail("File pos after read wrong %d" % f.tell())
|
|---|
| 199 |
|
|---|
| 200 | f.truncate()
|
|---|
| 201 | if f.tell() != 5:
|
|---|
| 202 | self.fail("File pos after ftruncate wrong %d" % f.tell())
|
|---|
| 203 |
|
|---|
| 204 | f.close()
|
|---|
| 205 | size = os.path.getsize(TESTFN)
|
|---|
| 206 | if size != 5:
|
|---|
| 207 | self.fail("File size after ftruncate wrong %d" % size)
|
|---|
| 208 |
|
|---|
| 209 | try:
|
|---|
| 210 | bug801631()
|
|---|
| 211 | finally:
|
|---|
| 212 | os.unlink(TESTFN)
|
|---|
| 213 |
|
|---|
| 214 | def testIteration(self):
|
|---|
| 215 | # Test the complex interaction when mixing file-iteration and the
|
|---|
| 216 | # various read* methods. Ostensibly, the mixture could just be tested
|
|---|
| 217 | # to work when it should work according to the Python language,
|
|---|
| 218 | # instead of fail when it should fail according to the current CPython
|
|---|
| 219 | # implementation. People don't always program Python the way they
|
|---|
| 220 | # should, though, and the implemenation might change in subtle ways,
|
|---|
| 221 | # so we explicitly test for errors, too; the test will just have to
|
|---|
| 222 | # be updated when the implementation changes.
|
|---|
| 223 | dataoffset = 16384
|
|---|
| 224 | filler = "ham\n"
|
|---|
| 225 | assert not dataoffset % len(filler), \
|
|---|
| 226 | "dataoffset must be multiple of len(filler)"
|
|---|
| 227 | nchunks = dataoffset // len(filler)
|
|---|
| 228 | testlines = [
|
|---|
| 229 | "spam, spam and eggs\n",
|
|---|
| 230 | "eggs, spam, ham and spam\n",
|
|---|
| 231 | "saussages, spam, spam and eggs\n",
|
|---|
| 232 | "spam, ham, spam and eggs\n",
|
|---|
| 233 | "spam, spam, spam, spam, spam, ham, spam\n",
|
|---|
| 234 | "wonderful spaaaaaam.\n"
|
|---|
| 235 | ]
|
|---|
| 236 | methods = [("readline", ()), ("read", ()), ("readlines", ()),
|
|---|
| 237 | ("readinto", (array("c", " "*100),))]
|
|---|
| 238 |
|
|---|
| 239 | try:
|
|---|
| 240 | # Prepare the testfile
|
|---|
| 241 | bag = open(TESTFN, "w")
|
|---|
| 242 | bag.write(filler * nchunks)
|
|---|
| 243 | bag.writelines(testlines)
|
|---|
| 244 | bag.close()
|
|---|
| 245 | # Test for appropriate errors mixing read* and iteration
|
|---|
| 246 | for methodname, args in methods:
|
|---|
| 247 | f = open(TESTFN)
|
|---|
| 248 | if f.next() != filler:
|
|---|
| 249 | self.fail, "Broken testfile"
|
|---|
| 250 | meth = getattr(f, methodname)
|
|---|
| 251 | try:
|
|---|
| 252 | meth(*args)
|
|---|
| 253 | except ValueError:
|
|---|
| 254 | pass
|
|---|
| 255 | else:
|
|---|
| 256 | self.fail("%s%r after next() didn't raise ValueError" %
|
|---|
| 257 | (methodname, args))
|
|---|
| 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 = open(TESTFN)
|
|---|
| 268 | for i in range(nchunks):
|
|---|
| 269 | f.next()
|
|---|
| 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("c", "\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.tostring()
|
|---|
| 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 | # Reading after iteration hit EOF shouldn't hurt either
|
|---|
| 309 | f = open(TESTFN)
|
|---|
| 310 | try:
|
|---|
| 311 | for line in f:
|
|---|
| 312 | pass
|
|---|
| 313 | try:
|
|---|
| 314 | f.readline()
|
|---|
| 315 | f.readinto(buf)
|
|---|
| 316 | f.read()
|
|---|
| 317 | f.readlines()
|
|---|
| 318 | except ValueError:
|
|---|
| 319 | self.fail("read* failed after next() consumed file")
|
|---|
| 320 | finally:
|
|---|
| 321 | f.close()
|
|---|
| 322 | finally:
|
|---|
| 323 | os.unlink(TESTFN)
|
|---|
| 324 |
|
|---|
| 325 |
|
|---|
| 326 | def test_main():
|
|---|
| 327 | # Historically, these tests have been sloppy about removing TESTFN.
|
|---|
|
|---|