1"""Unit tests for the memoryview 2 3XXX We need more tests! Some tests are in test_bytes 4""" 5 6import unittest 7import sys 8import gc 9import weakref 10import array 11from test import test_support 12import io 13import copy 14import pickle 15import warnings 16 17 18class AbstractMemoryTests: 19 source_bytes = b"abcdef" 20 21 @property 22 def _source(self): 23 return self.source_bytes 24 25 @property 26 def _types(self): 27 return filter(None, [self.ro_type, self.rw_type]) 28 29 def check_getitem_with_type(self, tp): 30 item = self.getitem_type 31 b = tp(self._source) 32 oldrefcount = sys.getrefcount(b) 33 m = self._view(b) 34 self.assertEqual(m[0], item(b"a")) 35 self.assertIsInstance(m[0], bytes) 36 self.assertEqual(m[5], item(b"f")) 37 self.assertEqual(m[-1], item(b"f")) 38 self.assertEqual(m[-6], item(b"a")) 39 # Bounds checking 40 self.assertRaises(IndexError, lambda: m[6]) 41 self.assertRaises(IndexError, lambda: m[-7]) 42 self.assertRaises(IndexError, lambda: m[sys.maxsize]) 43 self.assertRaises(IndexError, lambda: m[-sys.maxsize]) 44 # Type checking 45 self.assertRaises(TypeError, lambda: m[None]) 46 self.assertRaises(TypeError, lambda: m[0.0]) 47 self.assertRaises(TypeError, lambda: m["a"]) 48 m = None 49 self.assertEqual(sys.getrefcount(b), oldrefcount) 50 51 def test_getitem(self): 52 for tp in self._types: 53 self.check_getitem_with_type(tp) 54 55 def test_iter(self): 56 for tp in self._types: 57 b = tp(self._source) 58 m = self._view(b) 59 self.assertEqual(list(m), [m[i] for i in range(len(m))]) 60 61 def test_repr(self): 62 for tp in self._types: 63 b = tp(self._source) 64 m = self._view(b) 65 self.assertIsInstance(m.__repr__(), str) 66 67 def test_setitem_readonly(self): 68 if not self.ro_type: 69 self.skipTest("no read-only type to test") 70 b = self.ro_type(self._source) 71 oldrefcount = sys.getrefcount(b) 72 m = self._view(b) 73 def setitem(value): 74 m[0] = value 75 self.assertRaises(TypeError, setitem, b"a") 76 self.assertRaises(TypeError, setitem, 65) 77 self.assertRaises(TypeError, setitem, memoryview(b"a")) 78 m = None 79 self.assertEqual(sys.getrefcount(b), oldrefcount) 80 81 def test_setitem_writable(self): 82 if not self.rw_type: 83 self.skipTest("no writable type to test") 84 tp = self.rw_type 85 b = self.rw_type(self._source) 86 oldrefcount = sys.getrefcount(b) 87 m = self._view(b) 88 m[0] = tp(b"0") 89 self._check_contents(tp, b, b"0bcdef") 90 m[1:3] = tp(b"12") 91 self._check_contents(tp, b, b"012def") 92 m[1:1] = tp(b"") 93 self._check_contents(tp, b, b"012def") 94 m[:] = tp(b"abcdef") 95 self._check_contents(tp, b, b"abcdef") 96 97 # Overlapping copies of a view into itself 98 m[0:3] = m[2:5] 99 self._check_contents(tp, b, b"cdedef") 100 m[:] = tp(b"abcdef") 101 m[2:5] = m[0:3] 102 self._check_contents(tp, b, b"ababcf") 103 104 def setitem(key, value): 105 m[key] = tp(value) 106 # Bounds checking 107 self.assertRaises(IndexError, setitem, 6, b"a") 108 self.assertRaises(IndexError, setitem, -7, b"a") 109 self.assertRaises(IndexError, setitem, sys.maxsize, b"a") 110 self.assertRaises(IndexError, setitem, -sys.maxsize, b"a") 111 # Wrong index/slice types 112 self.assertRaises(TypeError, setitem, 0.0, b"a") 113 self.assertRaises(TypeError, setitem, (0,), b"a") 114 self.assertRaises(TypeError, setitem, "a", b"a") 115 # Trying to resize the memory object 116 self.assertRaises(ValueError, setitem, 0, b"") 117 self.assertRaises(ValueError, setitem, 0, b"ab") 118 self.assertRaises(ValueError, setitem, slice(1,1), b"a") 119 self.assertRaises(ValueError, setitem, slice(0,2), b"a") 120 121 m = None 122 self.assertEqual(sys.getrefcount(b), oldrefcount) 123 124 def test_delitem(self): 125 for tp in self._types: 126 b = tp(self._source) 127 m = self._view(b) 128 with self.assertRaises(TypeError): 129 del m[1] 130 with self.assertRaises(TypeError): 131 del m[1:4] 132 133 def test_tobytes(self): 134 for tp in self._types: 135 m = self._view(tp(self._source)) 136 b = m.tobytes() 137 # This calls self.getitem_type() on each separate byte of b"abcdef" 138 expected = b"".join( 139 self.getitem_type(c) for c in b"abcdef") 140 self.assertEqual(b, expected) 141 self.assertIsInstance(b, bytes) 142 143 def test_tolist(self): 144 for tp in self._types: 145 m = self._view(tp(self._source)) 146 l = m.tolist() 147 self.assertEqual(l, map(ord, b"abcdef")) 148 149 def test_compare(self): 150 # memoryviews can compare for equality with other objects 151 # having the buffer interface. 152 for tp in self._types: 153 m = self._view(tp(self._source)) 154 for tp_comp in self._types: 155 self.assertTrue(m == tp_comp(b"abcdef")) 156 self.assertFalse(m != tp_comp(b"abcdef")) 157 self.assertFalse(m == tp_comp(b"abcde")) 158 self.assertTrue(m != tp_comp(b"abcde")) 159 self.assertFalse(m == tp_comp(b"abcde1")) 160 self.assertTrue(m != tp_comp(b"abcde1")) 161 self.assertTrue(m == m) 162 self.assertTrue(m == m[:]) 163 self.assertTrue(m[0:6] == m[:]) 164 self.assertFalse(m[0:5] == m) 165 166 # Comparison with objects which don't support the buffer API 167 self.assertFalse(m == u"abcdef") 168 self.assertTrue(m != u"abcdef") 169 self.assertFalse(u"abcdef" == m) 170 self.assertTrue(u"abcdef" != m) 171 172 # Unordered comparisons are unimplemented, and therefore give 173 # arbitrary results (they raise a TypeError in py3k) 174 175 def check_attributes_with_type(self, tp): 176 m = self._view(tp(self._source)) 177 self.assertEqual(m.format, self.format) 178 self.assertIsInstance(m.format, str) 179 self.assertEqual(m.itemsize, self.itemsize) 180 self.assertEqual(m.ndim, 1) 181 self.assertEqual(m.shape, (6,)) 182 self.assertEqual(len(m), 6) 183 self.assertEqual(m.strides, (self.itemsize,)) 184 self.assertEqual(m.suboffsets, None) 185 return m 186 187 def test_attributes_readonly(self): 188 if not self.ro_type: 189 self.skipTest("no read-only type to test") 190 m = self.check_attributes_with_type(self.ro_type) 191 self.assertEqual(m.readonly, True) 192 193 def test_attributes_writable(self): 194 if not self.rw_type: 195 self.skipTest("no writable type to test") 196 m = self.check_attributes_with_type(self.rw_type) 197 self.assertEqual(m.readonly, False) 198 199 # Disabled: unicode uses the old buffer API in 2.x 200 201 #def test_getbuffer(self): 202 ## Test PyObject_GetBuffer() on a memoryview object. 203 #for tp in self._types: 204 #b = tp(self._source) 205 #oldrefcount = sys.getrefcount(b) 206 #m = self._view(b) 207 #oldviewrefcount = sys.getrefcount(m) 208 #s = unicode(m, "utf-8") 209 #self._check_contents(tp, b, s.encode("utf-8")) 210 #self.assertEqual(sys.getrefcount(m), oldviewrefcount) 211 #m = None 212 #self.assertEqual(sys.getrefcount(b), oldrefcount) 213 214 def test_gc(self): 215 for tp in self._types: 216 if not isinstance(tp, type): 217 # If tp is a factory rather than a plain type, skip 218 continue 219 220 class MySource(tp): 221 pass 222 class MyObject: 223 pass 224 225 # Create a reference cycle through a memoryview object 226 b = MySource(tp(b'abc')) 227 m = self._view(b) 228 o = MyObject() 229 b.m = m 230 b.o = o 231 wr = weakref.ref(o) 232 b = m = o = None 233 # The cycle must be broken 234 gc.collect() 235 self.assertTrue(wr() is None, wr()) 236 237 def test_writable_readonly(self): 238 # Issue #10451: memoryview incorrectly exposes a readonly 239 # buffer as writable causing a segfault if using mmap 240 tp = self.ro_type 241 if tp is None: 242 self.skipTest("no read-only type to test") 243 b = tp(self._source) 244 m = self._view(b) 245 i = io.BytesIO(b'ZZZZ') 246 self.assertRaises(TypeError, i.readinto, m) 247 248# Variations on source objects for the buffer: bytes-like objects, then arrays 249# with itemsize > 1. 250# NOTE: support for multi-dimensional objects is unimplemented. 251 252class BaseBytesMemoryTests(AbstractMemoryTests): 253 ro_type = bytes 254 rw_type = bytearray 255 getitem_type = bytes 256 itemsize = 1 257 format = 'B' 258 259# Disabled: array.array() does not support the new buffer API in 2.x 260 261#class BaseArrayMemoryTests(AbstractMemoryTests): 262 #ro_type = None 263 #rw_type = lambda self, b: array.array('i', map(ord, b)) 264 #getitem_type = lambda self, b: array.array('i', map(ord, b)).tostring() 265 #itemsize = array.array('i').itemsize 266 #format = 'i' 267 268 #def test_getbuffer(self): 269 ## XXX Test should be adapted for non-byte buffers 270 #pass 271 272 #def test_tolist(self): 273 ## XXX NotImplementedError: tolist() only supports byte views 274 #pass 275 276 277# Variations on indirection levels: memoryview, slice of memoryview, 278# slice of slice of memoryview. 279# This is important to test allocation subtleties. 280 281class BaseMemoryviewTests: 282 def _view(self, obj): 283 return memoryview(obj) 284 285 def _check_contents(self, tp, obj, contents): 286 self.assertEqual(obj, tp(contents)) 287 288class BaseMemorySliceTests: 289 source_bytes = b"XabcdefY" 290 291 def _view(self, obj): 292 m = memoryview(obj) 293 return m[1:7] 294 295 def _check_contents(self, tp, obj, contents): 296 self.assertEqual(obj[1:7], tp(contents)) 297 298 def test_refs(self): 299 for tp in self._types: 300 m = memoryview(tp(self._source)) 301 oldrefcount = sys.getrefcount(m) 302 m[1:2] 303 self.assertEqual(sys.getrefcount(m), oldrefcount) 304 305class BaseMemorySliceSliceTests: 306 source_bytes = b"XabcdefY" 307 308 def _view(self, obj): 309 m = memoryview(obj) 310 return m[:7][1:] 311 312 def _check_contents(self, tp, obj, contents): 313 self.assertEqual(obj[1:7], tp(contents)) 314 315 316# Concrete test classes 317 318class BytesMemoryviewTest(unittest.TestCase, 319 BaseMemoryviewTests, BaseBytesMemoryTests): 320 321 def test_constructor(self): 322 for tp in self._types: 323 ob = tp(self._source) 324 self.assertTrue(memoryview(ob)) 325 self.assertTrue(memoryview(object=ob)) 326 self.assertRaises(TypeError, memoryview) 327 self.assertRaises(TypeError, memoryview, ob, ob) 328 self.assertRaises(TypeError, memoryview, argument=ob) 329 self.assertRaises(TypeError, memoryview, ob, argument=True) 330 331#class ArrayMemoryviewTest(unittest.TestCase, 332 #BaseMemoryviewTests, BaseArrayMemoryTests): 333 334 #def test_array_assign(self): 335 ## Issue #4569: segfault when mutating a memoryview with itemsize != 1 336 #a = array.array('i', range(10)) 337 #m = memoryview(a) 338 #new_a = array.array('i', range(9, -1, -1)) 339 #m[:] = new_a 340 #self.assertEqual(a, new_a) 341 342 343class BytesMemorySliceTest(unittest.TestCase, 344 BaseMemorySliceTests, BaseBytesMemoryTests): 345 pass 346 347#class ArrayMemorySliceTest(unittest.TestCase, 348 #BaseMemorySliceTests, BaseArrayMemoryTests): 349 #pass 350 351class BytesMemorySliceSliceTest(unittest.TestCase, 352 BaseMemorySliceSliceTests, BaseBytesMemoryTests): 353 pass 354 355#class ArrayMemorySliceSliceTest(unittest.TestCase, 356 #BaseMemorySliceSliceTests, BaseArrayMemoryTests): 357 #pass 358 359 360class OtherTest(unittest.TestCase): 361 def test_copy(self): 362 m = memoryview(b'abc') 363 with self.assertRaises(TypeError), warnings.catch_warnings(): 364 warnings.filterwarnings('ignore', ".*memoryview", DeprecationWarning) 365 copy.copy(m) 366 367 @test_support.cpython_only 368 def test_pickle(self): 369 m = memoryview(b'abc') 370 for proto in range(2): 371 with self.assertRaises(TypeError): 372 pickle.dumps(m, proto) 373 with test_support.check_py3k_warnings( 374 (".*memoryview", DeprecationWarning)): 375 pickle.dumps(m, 2) 376 377 378 379def test_main(): 380 test_support.run_unittest(__name__) 381 382if __name__ == "__main__": 383 test_main() 384