diff options
author | Thomas Wouters <thomas@python.org> | 2007-08-28 15:28:19 +0000 |
---|---|---|
committer | Thomas Wouters <thomas@python.org> | 2007-08-28 15:28:19 +0000 |
commit | 3ccec68a05abae43cf74dc7821c61ba88ab6cb46 (patch) | |
tree | 07e97200d168eec13110e16a11b974310b8b550a /Lib/test | |
parent | 0f4a14b56fcbd939e60f424517db61ca6f2f3885 (diff) | |
download | cpython-git-3ccec68a05abae43cf74dc7821c61ba88ab6cb46.tar.gz |
Improve extended slicing support in builtin types and classes. Specifically:
- Specialcase extended slices that amount to a shallow copy the same way as
is done for simple slices, in the tuple, string and unicode case.
- Specialcase step-1 extended slices to optimize the common case for all
involved types.
- For lists, allow extended slice assignment of differing lengths as long
as the step is 1. (Previously, 'l[:2:1] = []' failed even though
'l[:2] = []' and 'l[:2:None] = []' do not.)
- Implement extended slicing for buffer, array, structseq, mmap and
UserString.UserString.
- Implement slice-object support (but not non-step-1 slice assignment) for
UserString.MutableString.
- Add tests for all new functionality.
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/list_tests.py | 2 | ||||
-rw-r--r-- | Lib/test/string_tests.py | 14 | ||||
-rwxr-xr-x | Lib/test/test_array.py | 34 | ||||
-rw-r--r-- | Lib/test/test_buffer.py | 29 | ||||
-rw-r--r-- | Lib/test/test_mmap.py | 34 | ||||
-rw-r--r-- | Lib/test/test_structseq.py | 12 | ||||
-rwxr-xr-x | Lib/test/test_userstring.py | 23 |
7 files changed, 146 insertions, 2 deletions
diff --git a/Lib/test/list_tests.py b/Lib/test/list_tests.py index 7c6623a22f..1c799d760e 100644 --- a/Lib/test/list_tests.py +++ b/Lib/test/list_tests.py @@ -179,8 +179,10 @@ class CommonTest(seq_tests.CommonTest): self.assertEqual(a, self.type2test(range(10))) self.assertRaises(TypeError, a.__setslice__, 0, 1, 5) + self.assertRaises(TypeError, a.__setitem__, slice(0, 1, 5)) self.assertRaises(TypeError, a.__setslice__) + self.assertRaises(TypeError, a.__setitem__) def test_delslice(self): a = self.type2test([0, 1]) diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index d38e4a98dd..d0f8c03c7e 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -912,7 +912,6 @@ class MixinStrUnicodeUserStringTest: self.checkequal(u'abc', 'abc', '__getitem__', slice(0, 1000)) self.checkequal(u'a', 'abc', '__getitem__', slice(0, 1)) self.checkequal(u'', 'abc', '__getitem__', slice(0, 0)) - # FIXME What about negative indices? This is handled differently by [] and __getitem__(slice) self.checkraises(TypeError, 'abc', '__getitem__', 'def') @@ -926,10 +925,21 @@ class MixinStrUnicodeUserStringTest: self.checkequal('', 'abc', '__getslice__', 1000, 1000) self.checkequal('', 'abc', '__getslice__', 2000, 1000) self.checkequal('', 'abc', '__getslice__', 2, 1) - # FIXME What about negative indizes? This is handled differently by [] and __getslice__ self.checkraises(TypeError, 'abc', '__getslice__', 'def') + def test_extended_getslice(self): + # Test extended slicing by comparing with list slicing. + s = string.ascii_letters + string.digits + indices = (0, None, 1, 3, 41, -1, -2, -37) + for start in indices: + for stop in indices: + # Skip step 0 (invalid) + for step in indices[1:]: + L = list(s)[start:stop:step] + self.checkequal(u"".join(L), s, '__getitem__', + slice(start, stop, step)) + def test_mul(self): self.checkequal('', 'abc', '__mul__', -1) self.checkequal('', 'abc', '__mul__', 0) diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index c10ad86eea..0bb7e53706 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -474,6 +474,18 @@ class BaseTest(unittest.TestCase): array.array(self.typecode) ) + def test_extended_getslice(self): + # Test extended slicing by comparing with list slicing + # (Assumes list conversion works correctly, too) + a = array.array(self.typecode, self.example) + indices = (0, None, 1, 3, 19, 100, -1, -2, -31, -100) + for start in indices: + for stop in indices: + # Everything except the initial 0 (invalid step) + for step in indices[1:]: + self.assertEqual(list(a[start:stop:step]), + list(a)[start:stop:step]) + def test_setslice(self): a = array.array(self.typecode, self.example) a[:1] = a @@ -557,12 +569,34 @@ class BaseTest(unittest.TestCase): a = array.array(self.typecode, self.example) self.assertRaises(TypeError, a.__setslice__, 0, 0, None) + self.assertRaises(TypeError, a.__setitem__, slice(0, 0), None) self.assertRaises(TypeError, a.__setitem__, slice(0, 1), None) b = array.array(self.badtypecode()) self.assertRaises(TypeError, a.__setslice__, 0, 0, b) + self.assertRaises(TypeError, a.__setitem__, slice(0, 0), b) self.assertRaises(TypeError, a.__setitem__, slice(0, 1), b) + def test_extended_set_del_slice(self): + indices = (0, None, 1, 3, 19, 100, -1, -2, -31, -100) + for start in indices: + for stop in indices: + # Everything except the initial 0 (invalid step) + for step in indices[1:]: + a = array.array(self.typecode, self.example) + L = list(a) + # Make sure we have a slice of exactly the right length, + # but with (hopefully) different data. + data = L[start:stop:step] + data.reverse() + L[start:stop:step] = data + a[start:stop:step] = array.array(self.typecode, data) + self.assertEquals(a, array.array(self.typecode, L)) + + del L[start:stop:step] + del a[start:stop:step] + self.assertEquals(a, array.array(self.typecode, L)) + def test_index(self): example = 2*self.example a = array.array(self.typecode, example) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py new file mode 100644 index 0000000000..3bede88bf9 --- /dev/null +++ b/Lib/test/test_buffer.py @@ -0,0 +1,29 @@ +"""Unit tests for buffer objects. + +For now, tests just new or changed functionality. + +""" + +import unittest +from test import test_support + +class BufferTests(unittest.TestCase): + + def test_extended_getslice(self): + # Test extended slicing by comparing with list slicing. + s = "".join(chr(c) for c in list(range(255, -1, -1))) + b = buffer(s) + indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300) + for start in indices: + for stop in indices: + # Skip step 0 (invalid) + for step in indices[1:]: + self.assertEqual(b[start:stop:step], + s[start:stop:step]) + + +def test_main(): + test_support.run_unittest(BufferTests) + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 0b53823076..769eaed0b1 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -306,6 +306,40 @@ class MmapTests(unittest.TestCase): m[x] = ch = chr(x & 255) self.assertEqual(m[x], ch) + def test_extended_getslice(self): + # Test extended slicing by comparing with list slicing. + s = "".join(chr(c) for c in reversed(range(256))) + m = mmap.mmap(-1, len(s)) + m[:] = s + self.assertEqual(m[:], s) + indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300) + for start in indices: + for stop in indices: + # Skip step 0 (invalid) + for step in indices[1:]: + self.assertEqual(m[start:stop:step], + s[start:stop:step]) + + def test_extended_set_del_slice(self): + # Test extended slicing by comparing with list slicing. + s = "".join(chr(c) for c in reversed(range(256))) + m = mmap.mmap(-1, len(s)) + indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300) + for start in indices: + for stop in indices: + # Skip invalid step 0 + for step in indices[1:]: + m[:] = s + self.assertEqual(m[:], s) + L = list(s) + # Make sure we have a slice of exactly the right length, + # but with different data. + data = L[start:stop:step] + data = "".join(reversed(data)) + L[start:stop:step] = data + m[start:stop:step] = data + self.assertEquals(m[:], "".join(L)) + def test_main(): run_unittest(MmapTests) diff --git a/Lib/test/test_structseq.py b/Lib/test/test_structseq.py index eb6d58104f..1af0583804 100644 --- a/Lib/test/test_structseq.py +++ b/Lib/test/test_structseq.py @@ -97,6 +97,18 @@ class StructSeqTest(unittest.TestCase): t = time.gmtime() x = t.__reduce__() + def test_extended_getslice(self): + # Test extended slicing by comparing with list slicing. + t = time.gmtime() + L = list(t) + indices = (0, None, 1, 3, 19, 300, -1, -2, -31, -300) + for start in indices: + for stop in indices: + # Skip step 0 (invalid) + for step in indices[1:]: + self.assertEqual(list(t[start:stop:step]), + L[start:stop:step]) + def test_main(): test_support.run_unittest(StructSeqTest) diff --git a/Lib/test/test_userstring.py b/Lib/test/test_userstring.py index 53114db285..b66dffe3f6 100755 --- a/Lib/test/test_userstring.py +++ b/Lib/test/test_userstring.py @@ -3,6 +3,7 @@ # UserString instances should behave similar to builtin string objects. import unittest +import string from test import test_support, string_tests from UserString import UserString, MutableString @@ -88,6 +89,28 @@ class MutableStringTest(UserStringTest): del s[-1:10] self.assertEqual(s, "fo") + def test_extended_set_del_slice(self): + indices = (0, None, 1, 3, 19, 100, -1, -2, -31, -100) + orig = string.ascii_letters + string.digits + for start in indices: + for stop in indices: + # Use indices[1:] when MutableString can handle real + # extended slices + for step in (None, 1, -1): + s = self.type2test(orig) + L = list(orig) + # Make sure we have a slice of exactly the right length, + # but with (hopefully) different data. + data = L[start:stop:step] + data.reverse() + L[start:stop:step] = data + s[start:stop:step] = "".join(data) + self.assertEquals(s, "".join(L)) + + del L[start:stop:step] + del s[start:stop:step] + self.assertEquals(s, "".join(L)) + def test_immutable(self): s = self.type2test("foobar") s2 = s.immutable() |