|
3 | 3 | from array import array |
4 | 4 | from weakref import proxy |
5 | 5 |
|
6 | | -from test.test_support import verify, TESTFN, TestFailed |
| 6 | +from test.test_support import verify, TESTFN, TestFailed, findfile |
7 | 7 | from UserList import UserList |
8 | 8 |
|
9 | 9 | # verify weak references |
@@ -228,3 +228,113 @@ def bug801631(): |
228 | 228 | bug801631() |
229 | 229 | finally: |
230 | 230 | os.unlink(TESTFN) |
| 231 | + |
| 232 | +# Test the complex interaction when mixing file-iteration and the various |
| 233 | +# read* methods. Ostensibly, the mixture could just be tested to work |
| 234 | +# when it should work according to the Python language, instead of fail |
| 235 | +# when it should fail according to the current CPython implementation. |
| 236 | +# People don't always program Python the way they should, though, and the |
| 237 | +# implemenation might change in subtle ways, so we explicitly test for |
| 238 | +# errors, too; the test will just have to be updated when the |
| 239 | +# implementation changes. |
| 240 | +dataoffset = 16384 |
| 241 | +filler = "ham\n" |
| 242 | +assert not dataoffset % len(filler), \ |
| 243 | + "dataoffset must be multiple of len(filler)" |
| 244 | +nchunks = dataoffset // len(filler) |
| 245 | +testlines = [ |
| 246 | + "spam, spam and eggs\n", |
| 247 | + "eggs, spam, ham and spam\n", |
| 248 | + "saussages, spam, spam and eggs\n", |
| 249 | + "spam, ham, spam and eggs\n", |
| 250 | + "spam, spam, spam, spam, spam, ham, spam\n", |
| 251 | + "wonderful spaaaaaam.\n" |
| 252 | +] |
| 253 | +methods = [("readline", ()), ("read", ()), ("readlines", ()), |
| 254 | + ("readinto", (array("c", " "*100),))] |
| 255 | + |
| 256 | +try: |
| 257 | + # Prepare the testfile |
| 258 | + bag = open(TESTFN, "w") |
| 259 | + bag.write(filler * nchunks) |
| 260 | + bag.writelines(testlines) |
| 261 | + bag.close() |
| 262 | + # Test for appropriate errors mixing read* and iteration |
| 263 | + for methodname, args in methods: |
| 264 | + f = open(TESTFN) |
| 265 | + if f.next() != filler: |
| 266 | + raise TestFailed, "Broken testfile" |
| 267 | + meth = getattr(f, methodname) |
| 268 | + try: |
| 269 | + meth(*args) |
| 270 | + except ValueError: |
| 271 | + pass |
| 272 | + else: |
| 273 | + raise TestFailed("%s%r after next() didn't raise ValueError" % |
| 274 | + (methodname, args)) |
| 275 | + f.close() |
| 276 | + |
| 277 | + # Test to see if harmless (by accident) mixing of read* and iteration |
| 278 | + # still works. This depends on the size of the internal iteration |
| 279 | + # buffer (currently 8192,) but we can test it in a flexible manner. |
| 280 | + # Each line in the bag o' ham is 4 bytes ("h", "a", "m", "\n"), so |
| 281 | + # 4096 lines of that should get us exactly on the buffer boundary for |
| 282 | + # any power-of-2 buffersize between 4 and 16384 (inclusive). |
| 283 | + f = open(TESTFN) |
| 284 | + for i in range(nchunks): |
| 285 | + f.next() |
| 286 | + testline = testlines.pop(0) |
| 287 | + try: |
| 288 | + line = f.readline() |
| 289 | + except ValueError: |
| 290 | + raise TestFailed("readline() after next() with supposedly empty " |
| 291 | + "iteration-buffer failed anyway") |
| 292 | + if line != testline: |
| 293 | + raise TestFailed("readline() after next() with empty buffer " |
| 294 | + "failed. Got %r, expected %r" % (line, testline)) |
| 295 | + testline = testlines.pop(0) |
| 296 | + buf = array("c", "\x00" * len(testline)) |
| 297 | + try: |
| 298 | + f.readinto(buf) |
| 299 | + except ValueError: |
| 300 | + raise TestFailed("readinto() after next() with supposedly empty " |
| 301 | + "iteration-buffer failed anyway") |
| 302 | + line = buf.tostring() |
| 303 | + if line != testline: |
| 304 | + raise TestFailed("readinto() after next() with empty buffer " |
| 305 | + "failed. Got %r, expected %r" % (line, testline)) |
| 306 | + |
| 307 | + testline = testlines.pop(0) |
| 308 | + try: |
| 309 | + line = f.read(len(testline)) |
| 310 | + except ValueError: |
| 311 | + raise TestFailed("read() after next() with supposedly empty " |
| 312 | + "iteration-buffer failed anyway") |
| 313 | + if line != testline: |
| 314 | + raise TestFailed("read() after next() with empty buffer " |
| 315 | + "failed. Got %r, expected %r" % (line, testline)) |
| 316 | + try: |
| 317 | + lines = f.readlines() |
| 318 | + except ValueError: |
| 319 | + raise TestFailed("readlines() after next() with supposedly empty " |
| 320 | + "iteration-buffer failed anyway") |
| 321 | + if lines != testlines: |
| 322 | + raise TestFailed("readlines() after next() with empty buffer " |
| 323 | + "failed. Got %r, expected %r" % (line, testline)) |
| 324 | + # Reading after iteration hit EOF shouldn't hurt either |
| 325 | + f = open(TESTFN) |
| 326 | + for line in f: |
| 327 | + pass |
| 328 | + try: |
| 329 | + f.readline() |
| 330 | + f.readinto(buf) |
| 331 | + f.read() |
| 332 | + f.readlines() |
| 333 | + except ValueError: |
| 334 | + raise TestFailed("read* failed after next() consumed file") |
| 335 | +finally: |
| 336 | + # Bare 'except' so as not to mask errors in the test |
| 337 | + try: |
| 338 | + os.unlink(TESTFN) |
| 339 | + except: |
| 340 | + pass |
0 commit comments