[Jython-checkins] jython: Fix index computation for StringBuilder after seek back in cStringIO

jim.baker jython-checkins at python.org
Wed Apr 15 17:09:14 CEST 2015


https://hg.python.org/jython/rev/ce136d0b598f
changeset:   7669:ce136d0b598f
user:        Jim Baker <jim.baker at rackspace.com>
date:        Wed Apr 15 11:09:09 2015 -0400
summary:
  Fix index computation for StringBuilder after seek back in cStringIO

Also updates test_StringIO to latest, then reapply Jython-specific FIXME
for subsequent work.

Fixes http://bugs.jython.org/issue2324

files:
  Lib/test/test_StringIO.py             |  48 ++++++++++++++-
  Lib/test/test_StringIO_jy.py          |  11 +++
  src/org/python/modules/cStringIO.java |   4 +-
  3 files changed, 59 insertions(+), 4 deletions(-)


diff --git a/Lib/test/test_StringIO.py b/Lib/test/test_StringIO.py
--- a/Lib/test/test_StringIO.py
+++ b/Lib/test/test_StringIO.py
@@ -5,6 +5,7 @@
 import cStringIO
 import types
 import array
+import sys
 from test import test_support
 
 
@@ -27,6 +28,8 @@
         eq = self.assertEqual
         self.assertRaises(TypeError, self._fp.seek)
         eq(self._fp.read(10), self._line[:10])
+        eq(self._fp.read(0), '')
+        eq(self._fp.readline(0), '')
         eq(self._fp.readline(), self._line[10:] + '\n')
         eq(len(self._fp.readlines(60)), 2)
         self._fp.seek(0)
@@ -105,6 +108,45 @@
         self._fp.close()
         self.assertRaises(ValueError, self._fp.getvalue)
 
+    @test_support.bigmemtest(test_support._2G + 2**26, memuse=2.001)
+    def test_reads_from_large_stream(self, size):
+        linesize = 2**26 # 64 MiB
+        lines = ['x' * (linesize - 1) + '\n'] * (size // linesize) + \
+                ['y' * (size % linesize)]
+        f = self.MODULE.StringIO(''.join(lines))
+        for i, expected in enumerate(lines):
+            line = f.read(len(expected))
+            self.assertEqual(len(line), len(expected))
+            self.assertEqual(line, expected)
+        self.assertEqual(f.read(), '')
+        f.seek(0)
+        for i, expected in enumerate(lines):
+            line = f.readline()
+            self.assertEqual(len(line), len(expected))
+            self.assertEqual(line, expected)
+        self.assertEqual(f.readline(), '')
+        f.seek(0)
+        self.assertEqual(f.readlines(), lines)
+        self.assertEqual(f.readlines(), [])
+        f.seek(0)
+        self.assertEqual(f.readlines(size), lines)
+        self.assertEqual(f.readlines(), [])
+
+    # In worst case cStringIO requires 2 + 1 + 1/2 + 1/2**2 + ... = 4
+    # bytes per input character.
+    @test_support.bigmemtest(test_support._2G, memuse=4)
+    def test_writes_to_large_stream(self, size):
+        s = 'x' * 2**26 # 64 MiB
+        f = self.MODULE.StringIO()
+        n = size
+        while n > len(s):
+            f.write(s)
+            n -= len(s)
+        s = None
+        f.write('x' * n)
+        self.assertEqual(len(f.getvalue()), size)
+
+
 class TestStringIO(TestGenericStringIO):
     MODULE = StringIO
 
@@ -153,8 +195,10 @@
         self.assertEqual(s, 'abcde')
         self.assertEqual(type(s), str)
 
-        # This cStringIO/StringIO difference seems CPython specific to me...
-        if not test_support.is_jython:
+        if not test_support.is_jython:  # FIXME re-enable in a future release
+            # On Jython, this should raise UnicodeEncodeError, however, we
+            # have to do more work on preventing inadvertent mixing of Unicode
+            # into String-supporting objects like StringBuilder
             self.assertRaises(UnicodeEncodeError, self.MODULE.StringIO, u'\xf4')
 
 
diff --git a/Lib/test/test_StringIO_jy.py b/Lib/test/test_StringIO_jy.py
--- a/Lib/test/test_StringIO_jy.py
+++ b/Lib/test/test_StringIO_jy.py
@@ -28,6 +28,17 @@
         f.write("uvwxyz")
         self.assertEqual(f.getvalue(), 'abcdef\x00\x00\x00\x00uvwxyz')
 
+    def test_write_seek_back_then_write(self):
+        # http://bugs.jython.org/issue2324
+        s = "abcdef"
+        for i in xrange(len(s)):
+            f = cStringIO.StringIO()
+            f.write(s)
+            f.seek(i)
+            f.write("x" * 47)
+            self.assertEqual(f.getvalue(), s[:i] + ("x" * 47))
+
+
 class TestGetValueAfterClose(unittest.TestCase):
 
     # This test, or something like it, should be really be pushed upstream
diff --git a/src/org/python/modules/cStringIO.java b/src/org/python/modules/cStringIO.java
--- a/src/org/python/modules/cStringIO.java
+++ b/src/org/python/modules/cStringIO.java
@@ -372,8 +372,8 @@
 
             if (spos < slen) {
                 if (newpos > slen) {
-                    buf.replace(spos, slen - spos, s);
-                    buf.append(s.substring(slen));
+                    buf.replace(spos, slen, s);
+                    buf.append(s.substring(slen - spos));
                     slen = newpos;
                 } else {
                     buf.replace(spos, spos + s.length(), s);

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list