blob: 0bfddd97ed646d55aed611b7a0c9f5dca6b6def9 [file] [log] [blame]
Christian Heimes7b6fc8e2007-11-08 02:28:11 +00001"""Unit tests for the memoryview
2
3XXX We need more tests! Some tests are in test_bytes
4"""
5
6import unittest
Benjamin Petersonee8712c2008-05-20 21:35:26 +00007import test.support
Antoine Pitrou616d2852008-08-19 22:09:34 +00008import sys
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +00009import gc
10import weakref
Antoine Pitrouc3b39242009-01-03 16:59:18 +000011import array
Antoine Pitrouad62b032011-01-18 18:57:52 +000012import io
Christian Heimes7b6fc8e2007-11-08 02:28:11 +000013
Antoine Pitrou616d2852008-08-19 22:09:34 +000014
Antoine Pitrouc3b39242009-01-03 16:59:18 +000015class AbstractMemoryTests:
16 source_bytes = b"abcdef"
Antoine Pitrou616d2852008-08-19 22:09:34 +000017
Antoine Pitrouc3b39242009-01-03 16:59:18 +000018 @property
19 def _source(self):
20 return self.source_bytes
21
22 @property
23 def _types(self):
24 return filter(None, [self.ro_type, self.rw_type])
Antoine Pitrou616d2852008-08-19 22:09:34 +000025
26 def check_getitem_with_type(self, tp):
Antoine Pitrouc3b39242009-01-03 16:59:18 +000027 item = self.getitem_type
28 b = tp(self._source)
Antoine Pitrou616d2852008-08-19 22:09:34 +000029 oldrefcount = sys.getrefcount(b)
30 m = self._view(b)
Ezio Melottib3aedd42010-11-20 19:04:17 +000031 self.assertEqual(m[0], item(b"a"))
Ezio Melottie9615932010-01-24 19:26:24 +000032 self.assertIsInstance(m[0], bytes)
Ezio Melottib3aedd42010-11-20 19:04:17 +000033 self.assertEqual(m[5], item(b"f"))
34 self.assertEqual(m[-1], item(b"f"))
35 self.assertEqual(m[-6], item(b"a"))
Antoine Pitrou616d2852008-08-19 22:09:34 +000036 # Bounds checking
37 self.assertRaises(IndexError, lambda: m[6])
38 self.assertRaises(IndexError, lambda: m[-7])
39 self.assertRaises(IndexError, lambda: m[sys.maxsize])
40 self.assertRaises(IndexError, lambda: m[-sys.maxsize])
41 # Type checking
42 self.assertRaises(TypeError, lambda: m[None])
43 self.assertRaises(TypeError, lambda: m[0.0])
44 self.assertRaises(TypeError, lambda: m["a"])
45 m = None
Ezio Melottib3aedd42010-11-20 19:04:17 +000046 self.assertEqual(sys.getrefcount(b), oldrefcount)
Antoine Pitrou616d2852008-08-19 22:09:34 +000047
Antoine Pitrouc3b39242009-01-03 16:59:18 +000048 def test_getitem(self):
49 for tp in self._types:
50 self.check_getitem_with_type(tp)
Antoine Pitrou616d2852008-08-19 22:09:34 +000051
Raymond Hettinger159eac92009-06-23 20:38:54 +000052 def test_iter(self):
53 for tp in self._types:
54 b = tp(self._source)
55 m = self._view(b)
56 self.assertEqual(list(m), [m[i] for i in range(len(m))])
57
Antoine Pitrou616d2852008-08-19 22:09:34 +000058 def test_setitem_readonly(self):
Antoine Pitrouc3b39242009-01-03 16:59:18 +000059 if not self.ro_type:
60 return
61 b = self.ro_type(self._source)
Antoine Pitrou616d2852008-08-19 22:09:34 +000062 oldrefcount = sys.getrefcount(b)
63 m = self._view(b)
64 def setitem(value):
65 m[0] = value
66 self.assertRaises(TypeError, setitem, b"a")
67 self.assertRaises(TypeError, setitem, 65)
68 self.assertRaises(TypeError, setitem, memoryview(b"a"))
69 m = None
Ezio Melottib3aedd42010-11-20 19:04:17 +000070 self.assertEqual(sys.getrefcount(b), oldrefcount)
Antoine Pitrou616d2852008-08-19 22:09:34 +000071
72 def test_setitem_writable(self):
Antoine Pitrouc3b39242009-01-03 16:59:18 +000073 if not self.rw_type:
74 return
75 tp = self.rw_type
76 b = self.rw_type(self._source)
Antoine Pitrou616d2852008-08-19 22:09:34 +000077 oldrefcount = sys.getrefcount(b)
78 m = self._view(b)
Antoine Pitrouc3b39242009-01-03 16:59:18 +000079 m[0] = tp(b"0")
80 self._check_contents(tp, b, b"0bcdef")
81 m[1:3] = tp(b"12")
82 self._check_contents(tp, b, b"012def")
83 m[1:1] = tp(b"")
84 self._check_contents(tp, b, b"012def")
85 m[:] = tp(b"abcdef")
86 self._check_contents(tp, b, b"abcdef")
Antoine Pitrou616d2852008-08-19 22:09:34 +000087
88 # Overlapping copies of a view into itself
89 m[0:3] = m[2:5]
Antoine Pitrouc3b39242009-01-03 16:59:18 +000090 self._check_contents(tp, b, b"cdedef")
91 m[:] = tp(b"abcdef")
Antoine Pitrou616d2852008-08-19 22:09:34 +000092 m[2:5] = m[0:3]
Antoine Pitrouc3b39242009-01-03 16:59:18 +000093 self._check_contents(tp, b, b"ababcf")
Antoine Pitrou616d2852008-08-19 22:09:34 +000094
95 def setitem(key, value):
Antoine Pitrouc3b39242009-01-03 16:59:18 +000096 m[key] = tp(value)
Antoine Pitrou616d2852008-08-19 22:09:34 +000097 # Bounds checking
98 self.assertRaises(IndexError, setitem, 6, b"a")
99 self.assertRaises(IndexError, setitem, -7, b"a")
100 self.assertRaises(IndexError, setitem, sys.maxsize, b"a")
101 self.assertRaises(IndexError, setitem, -sys.maxsize, b"a")
102 # Wrong index/slice types
103 self.assertRaises(TypeError, setitem, 0.0, b"a")
104 self.assertRaises(TypeError, setitem, (0,), b"a")
105 self.assertRaises(TypeError, setitem, "a", b"a")
106 # Trying to resize the memory object
107 self.assertRaises(ValueError, setitem, 0, b"")
108 self.assertRaises(ValueError, setitem, 0, b"ab")
109 self.assertRaises(ValueError, setitem, slice(1,1), b"a")
110 self.assertRaises(ValueError, setitem, slice(0,2), b"a")
111
112 m = None
Ezio Melottib3aedd42010-11-20 19:04:17 +0000113 self.assertEqual(sys.getrefcount(b), oldrefcount)
Antoine Pitrou616d2852008-08-19 22:09:34 +0000114
Antoine Pitroue0793ba2010-09-01 21:14:16 +0000115 def test_delitem(self):
116 for tp in self._types:
117 b = tp(self._source)
118 m = self._view(b)
119 with self.assertRaises(TypeError):
120 del m[1]
121 with self.assertRaises(TypeError):
122 del m[1:4]
123
Antoine Pitrou616d2852008-08-19 22:09:34 +0000124 def test_tobytes(self):
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000125 for tp in self._types:
126 m = self._view(tp(self._source))
127 b = m.tobytes()
128 # This calls self.getitem_type() on each separate byte of b"abcdef"
129 expected = b"".join(
130 self.getitem_type(bytes([c])) for c in b"abcdef")
Ezio Melottib3aedd42010-11-20 19:04:17 +0000131 self.assertEqual(b, expected)
Ezio Melottie9615932010-01-24 19:26:24 +0000132 self.assertIsInstance(b, bytes)
Antoine Pitrou616d2852008-08-19 22:09:34 +0000133
134 def test_tolist(self):
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000135 for tp in self._types:
136 m = self._view(tp(self._source))
137 l = m.tolist()
Ezio Melottib3aedd42010-11-20 19:04:17 +0000138 self.assertEqual(l, list(b"abcdef"))
Antoine Pitrou616d2852008-08-19 22:09:34 +0000139
140 def test_compare(self):
141 # memoryviews can compare for equality with other objects
142 # having the buffer interface.
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000143 for tp in self._types:
144 m = self._view(tp(self._source))
145 for tp_comp in self._types:
146 self.assertTrue(m == tp_comp(b"abcdef"))
147 self.assertFalse(m != tp_comp(b"abcdef"))
148 self.assertFalse(m == tp_comp(b"abcde"))
149 self.assertTrue(m != tp_comp(b"abcde"))
150 self.assertFalse(m == tp_comp(b"abcde1"))
151 self.assertTrue(m != tp_comp(b"abcde1"))
152 self.assertTrue(m == m)
153 self.assertTrue(m == m[:])
154 self.assertTrue(m[0:6] == m[:])
155 self.assertFalse(m[0:5] == m)
Antoine Pitrou616d2852008-08-19 22:09:34 +0000156
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000157 # Comparison with objects which don't support the buffer API
158 self.assertFalse(m == "abcdef")
159 self.assertTrue(m != "abcdef")
160 self.assertFalse("abcdef" == m)
161 self.assertTrue("abcdef" != m)
Antoine Pitrou616d2852008-08-19 22:09:34 +0000162
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000163 # Unordered comparisons
164 for c in (m, b"abcdef"):
165 self.assertRaises(TypeError, lambda: m < c)
166 self.assertRaises(TypeError, lambda: c <= m)
167 self.assertRaises(TypeError, lambda: m >= c)
168 self.assertRaises(TypeError, lambda: c > m)
Antoine Pitrou616d2852008-08-19 22:09:34 +0000169
170 def check_attributes_with_type(self, tp):
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000171 m = self._view(tp(self._source))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000172 self.assertEqual(m.format, self.format)
173 self.assertEqual(m.itemsize, self.itemsize)
174 self.assertEqual(m.ndim, 1)
175 self.assertEqual(m.shape, (6,))
176 self.assertEqual(len(m), 6)
177 self.assertEqual(m.strides, (self.itemsize,))
178 self.assertEqual(m.suboffsets, None)
Antoine Pitrou616d2852008-08-19 22:09:34 +0000179 return m
180
181 def test_attributes_readonly(self):
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000182 if not self.ro_type:
183 return
184 m = self.check_attributes_with_type(self.ro_type)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000185 self.assertEqual(m.readonly, True)
Antoine Pitrou616d2852008-08-19 22:09:34 +0000186
187 def test_attributes_writable(self):
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000188 if not self.rw_type:
189 return
190 m = self.check_attributes_with_type(self.rw_type)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000191 self.assertEqual(m.readonly, False)
Antoine Pitrou616d2852008-08-19 22:09:34 +0000192
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000193 def test_getbuffer(self):
194 # Test PyObject_GetBuffer() on a memoryview object.
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000195 for tp in self._types:
196 b = tp(self._source)
197 oldrefcount = sys.getrefcount(b)
198 m = self._view(b)
199 oldviewrefcount = sys.getrefcount(m)
200 s = str(m, "utf-8")
201 self._check_contents(tp, b, s.encode("utf-8"))
Ezio Melottib3aedd42010-11-20 19:04:17 +0000202 self.assertEqual(sys.getrefcount(m), oldviewrefcount)
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000203 m = None
Ezio Melottib3aedd42010-11-20 19:04:17 +0000204 self.assertEqual(sys.getrefcount(b), oldrefcount)
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000205
206 def test_gc(self):
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000207 for tp in self._types:
208 if not isinstance(tp, type):
209 # If tp is a factory rather than a plain type, skip
210 continue
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000211
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000212 class MySource(tp):
213 pass
214 class MyObject:
215 pass
216
217 # Create a reference cycle through a memoryview object
218 b = MySource(tp(b'abc'))
219 m = self._view(b)
220 o = MyObject()
221 b.m = m
222 b.o = o
223 wr = weakref.ref(o)
224 b = m = o = None
225 # The cycle must be broken
226 gc.collect()
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000227 self.assertTrue(wr() is None, wr())
Antoine Pitrouc6b09eb2008-09-01 15:10:14 +0000228
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000229 def _check_released(self, m, tp):
Ezio Melottied3a7d22010-12-01 02:32:32 +0000230 check = self.assertRaisesRegex(ValueError, "released")
Antoine Pitrou6e6cc832010-09-09 12:59:39 +0000231 with check: bytes(m)
232 with check: m.tobytes()
233 with check: m.tolist()
234 with check: m[0]
235 with check: m[0] = b'x'
236 with check: len(m)
237 with check: m.format
238 with check: m.itemsize
239 with check: m.ndim
240 with check: m.readonly
241 with check: m.shape
242 with check: m.strides
243 with check:
244 with m:
245 pass
246 # str() and repr() still function
247 self.assertIn("released memory", str(m))
248 self.assertIn("released memory", repr(m))
249 self.assertEqual(m, m)
250 self.assertNotEqual(m, memoryview(tp(self._source)))
251 self.assertNotEqual(m, tp(self._source))
252
253 def test_contextmanager(self):
254 for tp in self._types:
255 b = tp(self._source)
256 m = self._view(b)
257 with m as cm:
258 self.assertIs(cm, m)
259 self._check_released(m, tp)
260 m = self._view(b)
261 # Can release explicitly inside the context manager
262 with m:
263 m.release()
264
265 def test_release(self):
266 for tp in self._types:
267 b = tp(self._source)
268 m = self._view(b)
269 m.release()
270 self._check_released(m, tp)
271 # Can be called a second time (it's a no-op)
272 m.release()
273 self._check_released(m, tp)
Antoine Pitrou616d2852008-08-19 22:09:34 +0000274
Antoine Pitrouad62b032011-01-18 18:57:52 +0000275 def test_writable_readonly(self):
276 # Issue #10451: memoryview incorrectly exposes a readonly
277 # buffer as writable causing a segfault if using mmap
278 tp = self.ro_type
279 if tp is None:
280 return
281 b = tp(self._source)
282 m = self._view(b)
283 i = io.BytesIO(b'ZZZZ')
284 self.assertRaises(TypeError, i.readinto, m)
285
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000286# Variations on source objects for the buffer: bytes-like objects, then arrays
287# with itemsize > 1.
288# NOTE: support for multi-dimensional objects is unimplemented.
Antoine Pitrou616d2852008-08-19 22:09:34 +0000289
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000290class BaseBytesMemoryTests(AbstractMemoryTests):
291 ro_type = bytes
292 rw_type = bytearray
293 getitem_type = bytes
294 itemsize = 1
295 format = 'B'
296
297class BaseArrayMemoryTests(AbstractMemoryTests):
298 ro_type = None
299 rw_type = lambda self, b: array.array('i', list(b))
Antoine Pitrou1ce3eb52010-09-01 20:29:34 +0000300 getitem_type = lambda self, b: array.array('i', list(b)).tobytes()
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000301 itemsize = array.array('i').itemsize
302 format = 'i'
303
304 def test_getbuffer(self):
305 # XXX Test should be adapted for non-byte buffers
306 pass
307
308 def test_tolist(self):
309 # XXX NotImplementedError: tolist() only supports byte views
310 pass
311
312
313# Variations on indirection levels: memoryview, slice of memoryview,
314# slice of slice of memoryview.
315# This is important to test allocation subtleties.
316
317class BaseMemoryviewTests:
Antoine Pitrou616d2852008-08-19 22:09:34 +0000318 def _view(self, obj):
319 return memoryview(obj)
320
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000321 def _check_contents(self, tp, obj, contents):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000322 self.assertEqual(obj, tp(contents))
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000323
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000324class BaseMemorySliceTests:
325 source_bytes = b"XabcdefY"
Antoine Pitrou616d2852008-08-19 22:09:34 +0000326
327 def _view(self, obj):
328 m = memoryview(obj)
329 return m[1:7]
330
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000331 def _check_contents(self, tp, obj, contents):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000332 self.assertEqual(obj[1:7], tp(contents))
Antoine Pitrou616d2852008-08-19 22:09:34 +0000333
334 def test_refs(self):
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000335 for tp in self._types:
336 m = memoryview(tp(self._source))
337 oldrefcount = sys.getrefcount(m)
338 m[1:2]
Ezio Melottib3aedd42010-11-20 19:04:17 +0000339 self.assertEqual(sys.getrefcount(m), oldrefcount)
Antoine Pitrou616d2852008-08-19 22:09:34 +0000340
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000341class BaseMemorySliceSliceTests:
342 source_bytes = b"XabcdefY"
Antoine Pitrou616d2852008-08-19 22:09:34 +0000343
344 def _view(self, obj):
345 m = memoryview(obj)
346 return m[:7][1:]
347
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000348 def _check_contents(self, tp, obj, contents):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000349 self.assertEqual(obj[1:7], tp(contents))
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000350
351
352# Concrete test classes
353
354class BytesMemoryviewTest(unittest.TestCase,
355 BaseMemoryviewTests, BaseBytesMemoryTests):
356
357 def test_constructor(self):
358 for tp in self._types:
359 ob = tp(self._source)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000360 self.assertTrue(memoryview(ob))
361 self.assertTrue(memoryview(object=ob))
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000362 self.assertRaises(TypeError, memoryview)
363 self.assertRaises(TypeError, memoryview, ob, ob)
364 self.assertRaises(TypeError, memoryview, argument=ob)
365 self.assertRaises(TypeError, memoryview, ob, argument=True)
366
367class ArrayMemoryviewTest(unittest.TestCase,
368 BaseMemoryviewTests, BaseArrayMemoryTests):
369
370 def test_array_assign(self):
371 # Issue #4569: segfault when mutating a memoryview with itemsize != 1
372 a = array.array('i', range(10))
373 m = memoryview(a)
374 new_a = array.array('i', range(9, -1, -1))
375 m[:] = new_a
Ezio Melottib3aedd42010-11-20 19:04:17 +0000376 self.assertEqual(a, new_a)
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000377
378
379class BytesMemorySliceTest(unittest.TestCase,
380 BaseMemorySliceTests, BaseBytesMemoryTests):
381 pass
382
383class ArrayMemorySliceTest(unittest.TestCase,
384 BaseMemorySliceTests, BaseArrayMemoryTests):
385 pass
386
387class BytesMemorySliceSliceTest(unittest.TestCase,
388 BaseMemorySliceSliceTests, BaseBytesMemoryTests):
389 pass
390
391class ArrayMemorySliceSliceTest(unittest.TestCase,
392 BaseMemorySliceSliceTests, BaseArrayMemoryTests):
393 pass
Antoine Pitrou616d2852008-08-19 22:09:34 +0000394
395
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000396def test_main():
Antoine Pitrouc3b39242009-01-03 16:59:18 +0000397 test.support.run_unittest(__name__)
Christian Heimes7b6fc8e2007-11-08 02:28:11 +0000398
399if __name__ == "__main__":
400 test_main()