summaryrefslogtreecommitdiff
path: root/tests/run/memslice.pyx
diff options
context:
space:
mode:
Diffstat (limited to 'tests/run/memslice.pyx')
-rw-r--r--tests/run/memslice.pyx1102
1 files changed, 1102 insertions, 0 deletions
diff --git a/tests/run/memslice.pyx b/tests/run/memslice.pyx
new file mode 100644
index 000000000..0d64f093b
--- /dev/null
+++ b/tests/run/memslice.pyx
@@ -0,0 +1,1102 @@
+# Tests the buffer access syntax functionality by constructing
+# mock buffer objects.
+#
+# Note that the buffers are mock objects created for testing
+# the buffer access behaviour -- for instance there is no flag
+# checking in the buffer objects (why test our test case?), rather
+# what we want to test is what is passed into the flags argument.
+#
+
+from __future__ import unicode_literals
+
+from cython cimport view
+
+__test__ = {}
+
+import sys
+import re
+exclude = []#re.compile('object').search]
+
+def testcase(func):
+ for e in exclude:
+ if e(func.__name__):
+ return func
+ doctest = func.__doc__
+ if sys.version_info >= (3,1,1):
+ doctest = doctest.replace('does not have the buffer interface',
+ 'does not support the buffer interface')
+ __test__[func.__name__] = doctest
+ return func
+
+
+include "mockbuffers.pxi"
+
+#
+# Buffer acquire and release tests
+#
+
+def nousage():
+ """
+ The challenge here is just compilation.
+ """
+ cdef int[:, :] buf
+
+@testcase
+def acquire_release(o1, o2):
+ """
+ >>> A = IntMockBuffer("A", range(6))
+ >>> B = IntMockBuffer("B", range(6))
+ >>> acquire_release(A, B)
+ acquired A
+ released A
+ acquired B
+ released B
+ >>> acquire_release(None, None)
+ >>> acquire_release(None, B)
+ acquired B
+ released B
+ """
+ cdef int[:] buf
+ buf = o1
+ buf = o2
+
+@testcase
+def acquire_raise(o):
+ """
+ Apparently, doctest won't handle mixed exceptions and print
+ stats, so need to circumvent this.
+
+ >>> A = IntMockBuffer("A", range(6))
+ >>> A.resetlog()
+ >>> acquire_raise(A)
+ Traceback (most recent call last):
+ ...
+ Exception: on purpose
+ >>> A.printlog()
+ acquired A
+ released A
+
+ """
+ cdef int[:] buf
+ buf = o
+ raise Exception("on purpose")
+
+@testcase
+def acquire_failure1():
+ """
+ >>> acquire_failure1()
+ acquired working
+ 0 3
+ 0 3
+ released working
+ """
+ cdef int[:] buf
+ buf = IntMockBuffer("working", range(4))
+ print buf[0], buf[3]
+ try:
+ buf = ErrorBuffer()
+ assert False
+ except Exception:
+ print buf[0], buf[3]
+
+@testcase
+def acquire_failure2():
+ """
+ >>> acquire_failure2()
+ acquired working
+ 0 3
+ 0 3
+ released working
+ """
+ cdef int[:] buf = IntMockBuffer("working", range(4))
+ print buf[0], buf[3]
+ try:
+ buf = ErrorBuffer()
+ assert False
+ except Exception:
+ print buf[0], buf[3]
+
+@testcase
+def acquire_failure3():
+ """
+ >>> acquire_failure3()
+ acquired working
+ 0 3
+ released working
+ acquired working
+ 0 3
+ released working
+ """
+ cdef int[:] buf
+ buf = IntMockBuffer("working", range(4))
+ print buf[0], buf[3]
+ try:
+ buf = object()
+ assert False
+ except Exception:
+ print buf[0], buf[3]
+
+
+@testcase
+def acquire_nonbuffer1(first, second=None):
+ """
+ >>> acquire_nonbuffer1(3)
+ Traceback (most recent call last):
+ ...
+ TypeError: 'int' does not have the buffer interface
+ >>> acquire_nonbuffer1(type)
+ Traceback (most recent call last):
+ ...
+ TypeError: 'type' does not have the buffer interface
+ >>> acquire_nonbuffer1(None, 2)
+ Traceback (most recent call last):
+ ...
+ TypeError: 'int' does not have the buffer interface
+ """
+ cdef int[:] buf
+ buf = first
+ buf = second
+
+@testcase
+def acquire_nonbuffer2():
+ """
+ >>> acquire_nonbuffer2()
+ acquired working
+ 0 3
+ released working
+ acquired working
+ 0 3
+ released working
+ """
+ cdef int[:] buf = IntMockBuffer("working", range(4))
+ print buf[0], buf[3]
+ try:
+ buf = ErrorBuffer
+ assert False
+ except Exception:
+ print buf[0], buf[3]
+
+
+@testcase
+def as_argument(int[:] bufarg, int n):
+ """
+ >>> A = IntMockBuffer("A", range(6))
+ >>> as_argument(A, 6)
+ acquired A
+ 0 1 2 3 4 5 END
+ released A
+ """
+ cdef int i
+ for i in range(n):
+ print bufarg[i],
+ print 'END'
+
+@testcase
+def as_argument_defval(int[:] bufarg=IntMockBuffer('default', range(6)), int n=6):
+ """
+ >>> as_argument_defval()
+ acquired default
+ 0 1 2 3 4 5 END
+ released default
+ >>> A = IntMockBuffer("A", range(6))
+ >>> as_argument_defval(A, 6)
+ acquired A
+ 0 1 2 3 4 5 END
+ released A
+ """
+ cdef int i
+ for i in range(n):
+ print bufarg[i],
+ print 'END'
+
+@testcase
+def cdef_assignment(obj, n):
+ """
+ >>> A = IntMockBuffer("A", range(6))
+ >>> cdef_assignment(A, 6)
+ acquired A
+ 0 1 2 3 4 5 END
+ released A
+
+ """
+ cdef int[:] buf = obj
+ cdef int i
+ for i in range(n):
+ print buf[i],
+ print 'END'
+
+@testcase
+def forin_assignment(objs, int pick):
+ """
+ >>> A = IntMockBuffer("A", range(6))
+ >>> B = IntMockBuffer("B", range(6))
+ >>> forin_assignment([A, B, A, A], 2)
+ acquired A
+ 2
+ released A
+ acquired B
+ 2
+ released B
+ acquired A
+ 2
+ released A
+ acquired A
+ 2
+ released A
+ """
+ cdef int[:] buf
+ for buf in objs:
+ print buf[pick]
+
+@testcase
+def cascaded_buffer_assignment(obj):
+ """
+ >>> A = IntMockBuffer("A", range(6))
+ >>> cascaded_buffer_assignment(A)
+ acquired A
+ acquired A
+ released A
+ released A
+ """
+ cdef int[:] a, b
+ a = b = obj
+
+@testcase
+def tuple_buffer_assignment1(a, b):
+ """
+ >>> A = IntMockBuffer("A", range(6))
+ >>> B = IntMockBuffer("B", range(6))
+ >>> tuple_buffer_assignment1(A, B)
+ acquired A
+ acquired B
+ released A
+ released B
+ """
+ cdef int[:] x, y
+ x, y = a, b
+
+@testcase
+def tuple_buffer_assignment2(tup):
+ """
+ >>> A = IntMockBuffer("A", range(6))
+ >>> B = IntMockBuffer("B", range(6))
+ >>> tuple_buffer_assignment2((A, B))
+ acquired A
+ acquired B
+ released A
+ released B
+ """
+ cdef int[:] x, y
+ x, y = tup
+
+@testcase
+def explicitly_release_buffer():
+ """
+ >>> explicitly_release_buffer()
+ acquired A
+ released A
+ After release
+ """
+ cdef int[:] x = IntMockBuffer("A", range(10))
+ del x
+ print "After release"
+
+#
+# Getting items and index bounds checking
+#
+@testcase
+def get_int_2d(int[:, :] buf, int i, int j):
+ """
+ >>> C = IntMockBuffer("C", range(6), (2,3))
+ >>> get_int_2d(C, 1, 1)
+ acquired C
+ released C
+ 4
+
+ Check negative indexing:
+ >>> get_int_2d(C, -1, 0)
+ acquired C
+ released C
+ 3
+ >>> get_int_2d(C, -1, -2)
+ acquired C
+ released C
+ 4
+ >>> get_int_2d(C, -2, -3)
+ acquired C
+ released C
+ 0
+
+ Out-of-bounds errors:
+ >>> get_int_2d(C, 2, 0)
+ Traceback (most recent call last):
+ ...
+ IndexError: Out of bounds on buffer access (axis 0)
+ >>> get_int_2d(C, 0, -4)
+ Traceback (most recent call last):
+ ...
+ IndexError: Out of bounds on buffer access (axis 1)
+ """
+ return buf[i, j]
+
+@testcase
+def get_int_2d_uintindex(int[:, :] buf, unsigned int i, unsigned int j):
+ """
+ Unsigned indexing:
+ >>> C = IntMockBuffer("C", range(6), (2,3))
+ >>> get_int_2d_uintindex(C, 0, 0)
+ acquired C
+ released C
+ 0
+ >>> get_int_2d_uintindex(C, 1, 2)
+ acquired C
+ released C
+ 5
+ """
+ # This is most interesting with regards to the C code
+ # generated.
+ return buf[i, j]
+
+@testcase
+def set_int_2d(int[:, :] buf, int i, int j, int value):
+ """
+ Uses get_int_2d to read back the value afterwards. For pure
+ unit test, one should support reading in MockBuffer instead.
+
+ >>> C = IntMockBuffer("C", range(6), (2,3))
+ >>> set_int_2d(C, 1, 1, 10)
+ acquired C
+ released C
+ >>> get_int_2d(C, 1, 1)
+ acquired C
+ released C
+ 10
+
+ Check negative indexing:
+ >>> set_int_2d(C, -1, 0, 3)
+ acquired C
+ released C
+ >>> get_int_2d(C, -1, 0)
+ acquired C
+ released C
+ 3
+
+ >>> set_int_2d(C, -1, -2, 8)
+ acquired C
+ released C
+ >>> get_int_2d(C, -1, -2)
+ acquired C
+ released C
+ 8
+
+ >>> set_int_2d(C, -2, -3, 9)
+ acquired C
+ released C
+ >>> get_int_2d(C, -2, -3)
+ acquired C
+ released C
+ 9
+
+ Out-of-bounds errors:
+ >>> set_int_2d(C, 2, 0, 19)
+ Traceback (most recent call last):
+ ...
+ IndexError: Out of bounds on buffer access (axis 0)
+ >>> set_int_2d(C, 0, -4, 19)
+ Traceback (most recent call last):
+ ...
+ IndexError: Out of bounds on buffer access (axis 1)
+
+ """
+ buf[i, j] = value
+
+@testcase
+def list_comprehension(int[:] buf, len):
+ """
+ >>> list_comprehension(IntMockBuffer(None, [1,2,3]), 3)
+ 1|2|3
+ """
+ cdef int i
+ print u"|".join([unicode(buf[i]) for i in range(len)])
+
+#
+# The negative_indices buffer option
+#
+@testcase
+def no_negative_indices(object[int, negative_indices=False] buf, int idx):
+ """
+ The most interesting thing here is to inspect the C source and
+ make sure optimal code is produced.
+
+ >>> A = IntMockBuffer(None, range(6))
+ >>> no_negative_indices(A, 3)
+ 3
+ >>> no_negative_indices(A, -1)
+ Traceback (most recent call last):
+ ...
+ IndexError: Out of bounds on buffer access (axis 0)
+ """
+ return buf[idx]
+
+@testcase
+@cython.wraparound(False)
+def wraparound_directive(int[:] buf, int pos_idx, int neg_idx):
+ """
+ Again, the most interesting thing here is to inspect the C source.
+
+ >>> A = IntMockBuffer(None, range(4))
+ >>> wraparound_directive(A, 2, -1)
+ 5
+ >>> wraparound_directive(A, -1, 2)
+ Traceback (most recent call last):
+ ...
+ IndexError: Out of bounds on buffer access (axis 0)
+ """
+ cdef int byneg
+ with cython.wraparound(True):
+ byneg = buf[neg_idx]
+ return buf[pos_idx] + byneg
+
+
+#
+# Test which flags are passed.
+#
+# @testcase
+# def readonly(obj):
+# """
+# >>> R = UnsignedShortMockBuffer("R", range(27), shape=(3, 3, 3))
+# >>> readonly(R)
+# acquired R
+# 25
+# released R
+# >>> [str(x) for x in R.recieved_flags] # Works in both py2 and py3
+# ['FORMAT', 'INDIRECT', 'ND', 'STRIDES']
+# """
+# cdef unsigned short int[:, :, :] buf = obj
+# print buf[2, 2, 1]
+
+@testcase
+def writable(obj):
+ """
+ >>> R = UnsignedShortMockBuffer("R", range(27), shape=(3, 3, 3))
+ >>> writable(R)
+ acquired R
+ released R
+ >>> [str(x) for x in R.recieved_flags] # Py2/3
+ ['FORMAT', 'ND', 'STRIDES', 'WRITABLE']
+ """
+ cdef unsigned short int[:, :, :] buf = obj
+ buf[2, 2, 1] = 23
+
+@testcase
+def strided(int[:] buf):
+ """
+ >>> A = IntMockBuffer("A", range(4))
+ >>> strided(A)
+ acquired A
+ released A
+ 2
+ >>> [str(x) for x in A.recieved_flags] # Py2/3
+ ['FORMAT', 'ND', 'STRIDES', 'WRITABLE']
+
+ Check that the suboffsets were patched back prior to release.
+ >>> A.release_ok
+ True
+ """
+ return buf[2]
+
+@testcase
+def c_contig(int[::1] buf):
+ """
+ >>> A = IntMockBuffer(None, range(4))
+ >>> c_contig(A)
+ 2
+ >>> [str(x) for x in A.recieved_flags]
+ ['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS']
+ """
+ return buf[2]
+
+@testcase
+def c_contig_2d(int[:, ::1] buf):
+ """
+ Multi-dim has seperate implementation
+
+ >>> A = IntMockBuffer(None, range(12), shape=(3,4))
+ >>> c_contig_2d(A)
+ 7
+ >>> [str(x) for x in A.recieved_flags]
+ ['FORMAT', 'ND', 'STRIDES', 'C_CONTIGUOUS']
+ """
+ return buf[1, 3]
+
+@testcase
+def f_contig(int[::1, :] buf):
+ """
+ >>> A = IntMockBuffer(None, range(4), shape=(2, 2))
+ >>> f_contig(A)
+ 2
+ >>> [str(x) for x in A.recieved_flags]
+ ['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS']
+ """
+ return buf[0, 1]
+
+@testcase
+def f_contig_2d(object[int, ndim=2, mode='fortran'] buf):
+ """
+ Must set up strides manually to ensure Fortran ordering.
+
+ >>> A = IntMockBuffer(None, range(12), shape=(4,3), strides=(1, 4))
+ >>> f_contig_2d(A)
+ 7
+ >>> [str(x) for x in A.recieved_flags]
+ ['FORMAT', 'ND', 'STRIDES', 'F_CONTIGUOUS']
+ """
+ return buf[3, 1]
+
+#
+# Test compiler options for bounds checking. We create an array with a
+# safe "boundary" (memory
+# allocated outside of what it published) and then check whether we get back
+# what we stored in the memory or an error.
+
+@testcase
+def safe_get(int[:] buf, int idx):
+ """
+ >>> A = IntMockBuffer(None, range(10), shape=(3,), offset=5)
+
+ Validate our testing buffer...
+ >>> safe_get(A, 0)
+ 5
+ >>> safe_get(A, 2)
+ 7
+ >>> safe_get(A, -3)
+ 5
+
+ Access outside it. This is already done above for bounds check
+ testing but we include it to tell the story right.
+
+ >>> safe_get(A, -4)
+ Traceback (most recent call last):
+ ...
+ IndexError: Out of bounds on buffer access (axis 0)
+ >>> safe_get(A, 3)
+ Traceback (most recent call last):
+ ...
+ IndexError: Out of bounds on buffer access (axis 0)
+ """
+ return buf[idx]
+
+@testcase
+@cython.boundscheck(False) # outer decorators should take precedence
+@cython.boundscheck(True)
+def unsafe_get(int[:] buf, int idx):
+ """
+ Access outside of the area the buffer publishes.
+ >>> A = IntMockBuffer(None, range(10), shape=(3,), offset=5)
+ >>> unsafe_get(A, -4)
+ 4
+ >>> unsafe_get(A, -5)
+ 3
+ >>> unsafe_get(A, 3)
+ 8
+ """
+ return buf[idx]
+
+# @testcase
+# @cython.boundscheck(False)
+# def unsafe_get_nonegative(object[int, negative_indices=False] buf, int idx):
+# """
+# Also inspect the C source to see that it is optimal...
+#
+# >>> A = IntMockBuffer(None, range(10), shape=(3,), offset=5)
+# >>> unsafe_get_nonegative(A, -2)
+# 3
+# """
+# return buf[idx]
+
+@testcase
+def mixed_get(int[:] buf, int unsafe_idx, int safe_idx):
+ """
+ >>> A = IntMockBuffer(None, range(10), shape=(3,), offset=5)
+ >>> mixed_get(A, -4, 0)
+ (4, 5)
+ >>> mixed_get(A, 0, -4)
+ Traceback (most recent call last):
+ ...
+ IndexError: Out of bounds on buffer access (axis 0)
+ """
+ with cython.boundscheck(False):
+ one = buf[unsafe_idx]
+ with cython.boundscheck(True):
+ two = buf[safe_idx]
+ return (one, two)
+
+#
+# Coercions
+#
+## @testcase
+## def coercions(object[unsigned char] uc):
+## """
+## TODO
+## """
+## print type(uc[0])
+## uc[0] = -1
+## print uc[0]
+## uc[0] = <int>3.14
+## print uc[0]
+
+## cdef char* ch = b"asfd"
+## cdef object[object] objbuf
+## objbuf[3] = ch
+
+
+#
+# Testing that accessing data using various types of buffer access
+# all works.
+#
+
+def printbuf_int(int[:] buf, shape):
+ # Utility func
+ cdef int i
+ for i in range(shape[0]):
+ print buf[i],
+ print 'END'
+
+
+@testcase
+def printbuf_int_2d(o, shape):
+ """
+ Strided:
+
+ >>> printbuf_int_2d(IntMockBuffer("A", range(6), (2,3)), (2,3))
+ acquired A
+ 0 1 2 END
+ 3 4 5 END
+ released A
+ >>> printbuf_int_2d(IntMockBuffer("A", range(100), (3,3), strides=(20,5)), (3,3))
+ acquired A
+ 0 5 10 END
+ 20 25 30 END
+ 40 45 50 END
+ released A
+
+ Indirect:
+ >>> printbuf_int_2d(IntMockBuffer("A", [[1,2],[3,4]]), (2,2))
+ acquired A
+ 1 2 END
+ 3 4 END
+ released A
+ """
+ # should make shape builtin
+ cdef int[:, :] buf
+ buf = o
+ cdef int i, j
+ for i in range(shape[0]):
+ for j in range(shape[1]):
+ print buf[i, j],
+ print 'END'
+
+@testcase
+def printbuf_float(o, shape):
+ """
+ >>> printbuf_float(FloatMockBuffer("F", [1.0, 1.25, 0.75, 1.0]), (4,))
+ acquired F
+ 1.0 1.25 0.75 1.0 END
+ released F
+ """
+
+ # should make shape builtin
+ cdef float[:] buf
+ buf = o
+ cdef int i, j
+ for i in range(shape[0]):
+ print buf[i],
+ print "END"
+
+
+#
+# Test assignments
+#
+@testcase
+def inplace_operators(int[:] buf):
+ """
+ >>> buf = IntMockBuffer(None, [2, 2])
+ >>> inplace_operators(buf)
+ >>> printbuf_int(buf, (2,))
+ 0 3 END
+ """
+ cdef int j = 0
+ buf[1] += 1
+ buf[j] *= 2
+ buf[0] -= 4
+
+
+
+#
+# Typedefs
+#
+# Test three layers of typedefs going through a h file for plain int, and
+# simply a header file typedef for floats and unsigned.
+
+ctypedef int td_cy_int
+cdef extern from "bufaccess.h":
+ ctypedef td_cy_int td_h_short # Defined as short, but Cython doesn't know this!
+ ctypedef float td_h_double # Defined as double
+ ctypedef unsigned int td_h_ushort # Defined as unsigned short
+ctypedef td_h_short td_h_cy_short
+
+@testcase
+def printbuf_td_cy_int(td_cy_int[:] buf, shape):
+ """
+ >>> printbuf_td_cy_int(IntMockBuffer(None, range(3)), (3,))
+ 0 1 2 END
+ >>> printbuf_td_cy_int(ShortMockBuffer(None, range(3)), (3,))
+ Traceback (most recent call last):
+ ...
+ ValueError: Buffer dtype mismatch, expected 'td_cy_int' but got 'short'
+ """
+ cdef int i
+ for i in range(shape[0]):
+ print buf[i],
+ print 'END'
+
+@testcase
+def printbuf_td_h_short(object[td_h_short] buf, shape):
+ """
+ >>> printbuf_td_h_short(ShortMockBuffer(None, range(3)), (3,))
+ 0 1 2 END
+ >>> printbuf_td_h_short(IntMockBuffer(None, range(3)), (3,))
+ Traceback (most recent call last):
+ ...
+ ValueError: Buffer dtype mismatch, expected 'td_h_short' but got 'int'
+ """
+ cdef int i
+ for i in range(shape[0]):
+ print buf[i],
+ print 'END'
+
+@testcase
+def printbuf_td_h_cy_short(object[td_h_cy_short] buf, shape):
+ """
+ >>> printbuf_td_h_cy_short(ShortMockBuffer(None, range(3)), (3,))
+ 0 1 2 END
+ >>> printbuf_td_h_cy_short(IntMockBuffer(None, range(3)), (3,))
+ Traceback (most recent call last):
+ ...
+ ValueError: Buffer dtype mismatch, expected 'td_h_cy_short' but got 'int'
+ """
+ cdef int i
+ for i in range(shape[0]):
+ print buf[i],
+ print 'END'
+
+@testcase
+def printbuf_td_h_ushort(object[td_h_ushort] buf, shape):
+ """
+ >>> printbuf_td_h_ushort(UnsignedShortMockBuffer(None, range(3)), (3,))
+ 0 1 2 END
+ >>> printbuf_td_h_ushort(ShortMockBuffer(None, range(3)), (3,))
+ Traceback (most recent call last):
+ ...
+ ValueError: Buffer dtype mismatch, expected 'td_h_ushort' but got 'short'
+ """
+ cdef int i
+ for i in range(shape[0]):
+ print buf[i],
+ print 'END'
+
+@testcase
+def printbuf_td_h_double(object[td_h_double] buf, shape):
+ """
+ >>> printbuf_td_h_double(DoubleMockBuffer(None, [0.25, 1, 3.125]), (3,))
+ 0.25 1.0 3.125 END
+ >>> printbuf_td_h_double(FloatMockBuffer(None, [0.25, 1, 3.125]), (3,))
+ Traceback (most recent call last):
+ ...
+ ValueError: Buffer dtype mismatch, expected 'td_h_double' but got 'float'
+ """
+ cdef int i
+ for i in range(shape[0]):
+ print buf[i],
+ print 'END'
+
+
+#
+# Object access
+#
+def addref(*args):
+ for item in args: Py_INCREF(item)
+def decref(*args):
+ for item in args: Py_DECREF(item)
+
+def get_refcount(x):
+ return (<PyObject*>x).ob_refcnt
+
+@testcase
+def printbuf_object(object[object] buf, shape):
+ """
+ Only play with unique objects, interned numbers etc. will have
+ unpredictable refcounts.
+
+ ObjectMockBuffer doesn't do anything about increfing/decrefing,
+ we to the "buffer implementor" refcounting directly in the
+ testcase.
+
+ >>> a, b, c = "globally_unique_string_23234123", {4:23}, [34,3]
+ >>> get_refcount(a), get_refcount(b), get_refcount(c)
+ (2, 2, 2)
+ >>> A = ObjectMockBuffer(None, [a, b, c])
+ >>> printbuf_object(A, (3,))
+ 'globally_unique_string_23234123' 2
+ {4: 23} 2
+ [34, 3] 2
+ """
+ cdef int i
+ for i in range(shape[0]):
+ print repr(buf[i]), (<PyObject*>buf[i]).ob_refcnt
+
+@testcase
+def assign_to_object(object[object] buf, int idx, obj):
+ """
+ See comments on printbuf_object above.
+
+ >>> a, b = [1, 2, 3], [4, 5, 6]
+ >>> get_refcount(a), get_refcount(b)
+ (2, 2)
+ >>> addref(a)
+ >>> A = ObjectMockBuffer(None, [1, a]) # 1, ...,otherwise it thinks nested lists...
+ >>> get_refcount(a), get_refcount(b)
+ (3, 2)
+ >>> assign_to_object(A, 1, b)
+ >>> get_refcount(a), get_refcount(b)
+ (2, 3)
+ >>> decref(b)
+ """
+ buf[idx] = obj
+
+@testcase
+def assign_temporary_to_object(object[object] buf):
+ """
+ See comments on printbuf_object above.
+
+ >>> a, b = [1, 2, 3], {4:23}
+ >>> get_refcount(a)
+ 2
+ >>> addref(a)
+ >>> A = ObjectMockBuffer(None, [b, a])
+ >>> get_refcount(a)
+ 3
+ >>> assign_temporary_to_object(A)
+ >>> get_refcount(a)
+ 2
+
+ >>> printbuf_object(A, (2,))
+ {4: 23} 2
+ {1: 8} 2
+
+ To avoid leaking a reference in our testcase we need to
+ replace the temporary with something we can manually decref :-)
+ >>> assign_to_object(A, 1, a)
+ >>> decref(a)
+ """
+ buf[1] = {3-2: 2+(2*4)-2}
+
+#
+# cast option
+#
+@testcase
+def buffer_cast(object[unsigned int, cast=True] buf, int idx):
+ """
+ Round-trip a signed int through unsigned int buffer access.
+
+ >>> A = IntMockBuffer(None, [-100])
+ >>> buffer_cast(A, 0)
+ -100
+ """
+ cdef unsigned int data = buf[idx]
+ return <int>data
+
+@testcase
+def buffer_cast_fails(object[char, cast=True] buf):
+ """
+ Cannot cast between datatype of different sizes.
+
+ >>> buffer_cast_fails(IntMockBuffer(None, [0]))
+ Traceback (most recent call last):
+ ...
+ ValueError: Item size of buffer (4 bytes) does not match size of 'char' (1 byte)
+ """
+ return buf[0]
+
+#
+# Typed buffers
+#
+@testcase
+def typedbuffer1(obj):
+ """
+ >>> typedbuffer1(IntMockBuffer("A", range(10)))
+ acquired A
+ released A
+ >>> typedbuffer1(None)
+ >>> typedbuffer1(4)
+ Traceback (most recent call last):
+ ...
+ TypeError: Cannot convert int to memslice.IntMockBuffer
+ """
+ cdef IntMockBuffer[int, ndim=1] buf = obj
+
+@testcase
+def typedbuffer2(IntMockBuffer[int, ndim=1] obj):
+ """
+ >>> typedbuffer2(IntMockBuffer("A", range(10)))
+ acquired A
+ released A
+ >>> typedbuffer2(None)
+ >>> typedbuffer2(4)
+ Traceback (most recent call last):
+ ...
+ TypeError: Argument 'obj' has incorrect type (expected memslice.IntMockBuffer, got int)
+ """
+ pass
+
+#
+# Test __cythonbufferdefaults__
+#
+@testcase
+def bufdefaults1(IntStridedMockBuffer[int, ndim=1] buf):
+ """
+ For IntStridedMockBuffer, mode should be
+ "strided" by defaults which should show
+ up in the flags.
+
+ >>> A = IntStridedMockBuffer("A", range(10))
+ >>> bufdefaults1(A)
+ acquired A
+ released A
+ >>> [str(x) for x in A.recieved_flags]
+ ['FORMAT', 'ND', 'STRIDES']
+ """
+ pass
+
+
+@testcase
+def basic_struct(object[MyStruct] buf):
+ """
+ See also buffmt.pyx
+
+ >>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
+ 1 2 3 4 5
+ >>> basic_struct(MyStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="bbqii"))
+ 1 2 3 4 5
+ """
+ print buf[0].a, buf[0].b, buf[0].c, buf[0].d, buf[0].e
+
+@testcase
+def nested_struct(object[NestedStruct] buf):
+ """
+ See also buffmt.pyx
+
+ >>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
+ 1 2 3 4 5
+ >>> nested_struct(NestedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="T{ii}T{2i}i"))
+ 1 2 3 4 5
+ """
+ print buf[0].x.a, buf[0].x.b, buf[0].y.a, buf[0].y.b, buf[0].z
+
+@testcase
+def packed_struct(object[PackedStruct] buf):
+ """
+ See also buffmt.pyx
+
+ >>> packed_struct(PackedStructMockBuffer(None, [(1, 2)]))
+ 1 2
+ >>> packed_struct(PackedStructMockBuffer(None, [(1, 2)], format="T{c^i}"))
+ 1 2
+ >>> packed_struct(PackedStructMockBuffer(None, [(1, 2)], format="T{c=i}"))
+ 1 2
+
+ """
+ print buf[0].a, buf[0].b
+
+@testcase
+def nested_packed_struct(object[NestedPackedStruct] buf):
+ """
+ See also buffmt.pyx
+
+ >>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)]))
+ 1 2 3 4 5
+ >>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="ci^ci@i"))
+ 1 2 3 4 5
+ >>> nested_packed_struct(NestedPackedStructMockBuffer(None, [(1, 2, 3, 4, 5)], format="^c@i^ci@i"))
+ 1 2 3 4 5
+ """
+ print buf[0].a, buf[0].b, buf[0].sub.a, buf[0].sub.b, buf[0].c
+
+cdef struct LongComplex:
+ long double real
+ long double imag
+
+cdef class LongComplexMockBuffer(MockBuffer):
+ cdef int write(self, char* buf, object value) except -1:
+ cdef LongComplex* s
+ s = <LongComplex*>buf;
+ s.real, s.imag = value
+ return 0
+
+ cdef get_itemsize(self): return sizeof(LongComplex)
+ cdef get_default_format(self): return b"Zg"
+
+#cdef extern from "complex.h":
+# pass
+
+@testcase
+def complex_dtype(object[long double complex] buf):
+ """
+ >>> complex_dtype(LongComplexMockBuffer(None, [(0, -1)]))
+ -1j
+ """
+ print buf[0]
+
+@testcase
+def complex_inplace(object[long double complex] buf):
+ """
+ >>> complex_inplace(LongComplexMockBuffer(None, [(0, -1)]))
+ (1+1j)
+ """
+ buf[0] = buf[0] + 1 + 2j
+ print buf[0]
+
+@testcase
+def complex_struct_dtype(object[LongComplex] buf):
+ """
+ Note that the format string is "Zg" rather than "2g", yet a struct
+ is accessed.
+ >>> complex_struct_dtype(LongComplexMockBuffer(None, [(0, -1)]))
+ 0.0 -1.0
+ """
+ print buf[0].real, buf[0].imag
+
+@testcase
+def complex_struct_inplace(object[LongComplex] buf):
+ """
+ >>> complex_struct_inplace(LongComplexMockBuffer(None, [(0, -1)]))
+ 1.0 1.0
+ """
+ buf[0].real += 1
+ buf[0].imag += 2
+ print buf[0].real, buf[0].imag
+
+#
+# Nogil
+#
+@testcase
+@cython.boundscheck(False)
+def buffer_nogil():
+ """
+ >>> buffer_nogil()
+ 10
+ """
+ cdef int[:] buf = IntMockBuffer(None, [1,2,3])
+ with nogil:
+ buf[1] = 10
+ return buf[1]