• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from ctypes import *
2import array
3import gc
4import unittest
5
6class X(Structure):
7    _fields_ = [("c_int", c_int)]
8    init_called = False
9    def __init__(self):
10        self._init_called = True
11
12class Test(unittest.TestCase):
13    def test_from_buffer(self):
14        a = array.array("i", range(16))
15        x = (c_int * 16).from_buffer(a)
16
17        y = X.from_buffer(a)
18        self.assertEqual(y.c_int, a[0])
19        self.assertFalse(y.init_called)
20
21        self.assertEqual(x[:], a.tolist())
22
23        a[0], a[-1] = 200, -200
24        self.assertEqual(x[:], a.tolist())
25
26        self.assertRaises(BufferError, a.append, 100)
27        self.assertRaises(BufferError, a.pop)
28
29        del x; del y; gc.collect(); gc.collect(); gc.collect()
30        a.append(100)
31        a.pop()
32        x = (c_int * 16).from_buffer(a)
33
34        self.assertIn(a, [obj.obj if isinstance(obj, memoryview) else obj
35                          for obj in x._objects.values()])
36
37        expected = x[:]
38        del a; gc.collect(); gc.collect(); gc.collect()
39        self.assertEqual(x[:], expected)
40
41        with self.assertRaisesRegex(TypeError, "not writable"):
42            (c_char * 16).from_buffer(b"a" * 16)
43        with self.assertRaisesRegex(TypeError, "not writable"):
44            (c_char * 16).from_buffer(memoryview(b"a" * 16))
45        with self.assertRaisesRegex(TypeError, "not C contiguous"):
46            (c_char * 16).from_buffer(memoryview(bytearray(b"a" * 16))[::-1])
47        msg = "bytes-like object is required"
48        with self.assertRaisesRegex(TypeError, msg):
49            (c_char * 16).from_buffer("a" * 16)
50
51    def test_fortran_contiguous(self):
52        try:
53            import _testbuffer
54        except ImportError as err:
55            self.skipTest(str(err))
56        flags = _testbuffer.ND_WRITABLE | _testbuffer.ND_FORTRAN
57        array = _testbuffer.ndarray(
58            [97] * 16, format="B", shape=[4, 4], flags=flags)
59        with self.assertRaisesRegex(TypeError, "not C contiguous"):
60            (c_char * 16).from_buffer(array)
61        array = memoryview(array)
62        self.assertTrue(array.f_contiguous)
63        self.assertFalse(array.c_contiguous)
64        with self.assertRaisesRegex(TypeError, "not C contiguous"):
65            (c_char * 16).from_buffer(array)
66
67    def test_from_buffer_with_offset(self):
68        a = array.array("i", range(16))
69        x = (c_int * 15).from_buffer(a, sizeof(c_int))
70
71        self.assertEqual(x[:], a.tolist()[1:])
72        with self.assertRaises(ValueError):
73            c_int.from_buffer(a, -1)
74        with self.assertRaises(ValueError):
75            (c_int * 16).from_buffer(a, sizeof(c_int))
76        with self.assertRaises(ValueError):
77            (c_int * 1).from_buffer(a, 16 * sizeof(c_int))
78
79    def test_from_buffer_memoryview(self):
80        a = [c_char.from_buffer(memoryview(bytearray(b'a')))]
81        a.append(a)
82        del a
83        gc.collect()  # Should not crash
84
85    def test_from_buffer_copy(self):
86        a = array.array("i", range(16))
87        x = (c_int * 16).from_buffer_copy(a)
88
89        y = X.from_buffer_copy(a)
90        self.assertEqual(y.c_int, a[0])
91        self.assertFalse(y.init_called)
92
93        self.assertEqual(x[:], list(range(16)))
94
95        a[0], a[-1] = 200, -200
96        self.assertEqual(x[:], list(range(16)))
97
98        a.append(100)
99        self.assertEqual(x[:], list(range(16)))
100
101        self.assertEqual(x._objects, None)
102
103        del a; gc.collect(); gc.collect(); gc.collect()
104        self.assertEqual(x[:], list(range(16)))
105
106        x = (c_char * 16).from_buffer_copy(b"a" * 16)
107        self.assertEqual(x[:], b"a" * 16)
108        with self.assertRaises(TypeError):
109            (c_char * 16).from_buffer_copy("a" * 16)
110
111    def test_from_buffer_copy_with_offset(self):
112        a = array.array("i", range(16))
113        x = (c_int * 15).from_buffer_copy(a, sizeof(c_int))
114
115        self.assertEqual(x[:], a.tolist()[1:])
116        with self.assertRaises(ValueError):
117            c_int.from_buffer_copy(a, -1)
118        with self.assertRaises(ValueError):
119            (c_int * 16).from_buffer_copy(a, sizeof(c_int))
120        with self.assertRaises(ValueError):
121            (c_int * 1).from_buffer_copy(a, 16 * sizeof(c_int))
122
123    def test_abstract(self):
124        from ctypes import _Pointer, _SimpleCData, _CFuncPtr
125
126        self.assertRaises(TypeError, Array.from_buffer, bytearray(10))
127        self.assertRaises(TypeError, Structure.from_buffer, bytearray(10))
128        self.assertRaises(TypeError, Union.from_buffer, bytearray(10))
129        self.assertRaises(TypeError, _CFuncPtr.from_buffer, bytearray(10))
130        self.assertRaises(TypeError, _Pointer.from_buffer, bytearray(10))
131        self.assertRaises(TypeError, _SimpleCData.from_buffer, bytearray(10))
132
133        self.assertRaises(TypeError, Array.from_buffer_copy, b"123")
134        self.assertRaises(TypeError, Structure.from_buffer_copy, b"123")
135        self.assertRaises(TypeError, Union.from_buffer_copy, b"123")
136        self.assertRaises(TypeError, _CFuncPtr.from_buffer_copy, b"123")
137        self.assertRaises(TypeError, _Pointer.from_buffer_copy, b"123")
138        self.assertRaises(TypeError, _SimpleCData.from_buffer_copy, b"123")
139
140if __name__ == '__main__':
141    unittest.main()
142