diff options
author | Thomas Wouters <thomas@python.org> | 2006-02-12 11:53:32 (GMT) |
---|---|---|
committer | Thomas Wouters <thomas@python.org> | 2006-02-12 11:53:32 (GMT) |
commit | c45251a48542e0074ad9865143359bdfec0f8467 (patch) | |
tree | 7d61df776dd020be7437f505c1f7ef4cc1779f2c /Lib/test | |
parent | f5b3e36493da275334e29afdbd238863697dca35 (diff) | |
download | cpython-c45251a48542e0074ad9865143359bdfec0f8467.zip cpython-c45251a48542e0074ad9865143359bdfec0f8467.tar.gz cpython-c45251a48542e0074ad9865143359bdfec0f8467.tar.bz2 |
SF patch #1397960: When mixing file-iteration and
readline/readlines/read/readinto, loudly break by raising ValueError, rather
than silently deliver data out of order or hitting EOF prematurely.
Probably not a bugfix candidate, even though it affects no 'working' code.
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_file.py | 112 |
1 files changed, 111 insertions, 1 deletions
diff --git a/Lib/test/test_file.py b/Lib/test/test_file.py index bde3202..69501df 100644 --- a/Lib/test/test_file.py +++ b/Lib/test/test_file.py @@ -3,7 +3,7 @@ import os from array import array from weakref import proxy -from test.test_support import verify, TESTFN, TestFailed +from test.test_support import verify, TESTFN, TestFailed, findfile from UserList import UserList # verify weak references @@ -228,3 +228,113 @@ try: bug801631() finally: os.unlink(TESTFN) + +# Test the complex interaction when mixing file-iteration and the various +# read* methods. Ostensibly, the mixture could just be tested to work +# when it should work according to the Python language, instead of fail +# when it should fail according to the current CPython implementation. +# People don't always program Python the way they should, though, and the +# implemenation might change in subtle ways, so we explicitly test for +# errors, too; the test will just have to be updated when the +# implementation changes. +dataoffset = 16384 +filler = "ham\n" +assert not dataoffset % len(filler), \ + "dataoffset must be multiple of len(filler)" +nchunks = dataoffset // len(filler) +testlines = [ + "spam, spam and eggs\n", + "eggs, spam, ham and spam\n", + "saussages, spam, spam and eggs\n", + "spam, ham, spam and eggs\n", + "spam, spam, spam, spam, spam, ham, spam\n", + "wonderful spaaaaaam.\n" +] +methods = [("readline", ()), ("read", ()), ("readlines", ()), + ("readinto", (array("c", " "*100),))] + +try: + # Prepare the testfile + bag = open(TESTFN, "w") + bag.write(filler * nchunks) + bag.writelines(testlines) + bag.close() + # Test for appropriate errors mixing read* and iteration + for methodname, args in methods: + f = open(TESTFN) + if f.next() != filler: + raise TestFailed, "Broken testfile" + meth = getattr(f, methodname) + try: + meth(*args) + except ValueError: + pass + else: + raise TestFailed("%s%r after next() didn't raise ValueError" % + (methodname, args)) + f.close() + + # Test to see if harmless (by accident) mixing of read* and iteration + # still works. This depends on the size of the internal iteration + # buffer (currently 8192,) but we can test it in a flexible manner. + # Each line in the bag o' ham is 4 bytes ("h", "a", "m", "\n"), so + # 4096 lines of that should get us exactly on the buffer boundary for + # any power-of-2 buffersize between 4 and 16384 (inclusive). + f = open(TESTFN) + for i in range(nchunks): + f.next() + testline = testlines.pop(0) + try: + line = f.readline() + except ValueError: + raise TestFailed("readline() after next() with supposedly empty " + "iteration-buffer failed anyway") + if line != testline: + raise TestFailed("readline() after next() with empty buffer " + "failed. Got %r, expected %r" % (line, testline)) + testline = testlines.pop(0) + buf = array("c", "\x00" * len(testline)) + try: + f.readinto(buf) + except ValueError: + raise TestFailed("readinto() after next() with supposedly empty " + "iteration-buffer failed anyway") + line = buf.tostring() + if line != testline: + raise TestFailed("readinto() after next() with empty buffer " + "failed. Got %r, expected %r" % (line, testline)) + + testline = testlines.pop(0) + try: + line = f.read(len(testline)) + except ValueError: + raise TestFailed("read() after next() with supposedly empty " + "iteration-buffer failed anyway") + if line != testline: + raise TestFailed("read() after next() with empty buffer " + "failed. Got %r, expected %r" % (line, testline)) + try: + lines = f.readlines() + except ValueError: + raise TestFailed("readlines() after next() with supposedly empty " + "iteration-buffer failed anyway") + if lines != testlines: + raise TestFailed("readlines() after next() with empty buffer " + "failed. Got %r, expected %r" % (line, testline)) + # Reading after iteration hit EOF shouldn't hurt either + f = open(TESTFN) + for line in f: + pass + try: + f.readline() + f.readinto(buf) + f.read() + f.readlines() + except ValueError: + raise TestFailed("read* failed after next() consumed file") +finally: + # Bare 'except' so as not to mask errors in the test + try: + os.unlink(TESTFN) + except: + pass |