• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import unittest
2import pickle
3from ctypes import *
4import _ctypes_test
5dll = CDLL(_ctypes_test.__file__)
6
7class X(Structure):
8    _fields_ = [("a", c_int), ("b", c_double)]
9    init_called = 0
10    def __init__(self, *args, **kw):
11        X.init_called += 1
12        self.x = 42
13
14class Y(X):
15    _fields_ = [("str", c_char_p)]
16
17class PickleTest:
18    def dumps(self, item):
19        return pickle.dumps(item, self.proto)
20
21    def loads(self, item):
22        return pickle.loads(item)
23
24    def test_simple(self):
25        for src in [
26            c_int(42),
27            c_double(3.14),
28            ]:
29            dst = self.loads(self.dumps(src))
30            self.assertEqual(src.__dict__, dst.__dict__)
31            self.assertEqual(memoryview(src).tobytes(),
32                                 memoryview(dst).tobytes())
33
34    def test_struct(self):
35        X.init_called = 0
36
37        x = X()
38        x.a = 42
39        self.assertEqual(X.init_called, 1)
40
41        y = self.loads(self.dumps(x))
42
43        # loads must NOT call __init__
44        self.assertEqual(X.init_called, 1)
45
46        # ctypes instances are identical when the instance __dict__
47        # and the memory buffer are identical
48        self.assertEqual(y.__dict__, x.__dict__)
49        self.assertEqual(memoryview(y).tobytes(),
50                             memoryview(x).tobytes())
51
52    def test_unpickable(self):
53        # ctypes objects that are pointers or contain pointers are
54        # unpickable.
55        self.assertRaises(ValueError, lambda: self.dumps(Y()))
56
57        prototype = CFUNCTYPE(c_int)
58
59        for item in [
60            c_char_p(),
61            c_wchar_p(),
62            c_void_p(),
63            pointer(c_int(42)),
64            dll._testfunc_p_p,
65            prototype(lambda: 42),
66            ]:
67            self.assertRaises(ValueError, lambda: self.dumps(item))
68
69    def test_wchar(self):
70        self.dumps(c_char(b"x"))
71        # Issue 5049
72        self.dumps(c_wchar("x"))
73
74for proto in range(pickle.HIGHEST_PROTOCOL + 1):
75    name = 'PickleTest_%s' % proto
76    globals()[name] = type(name,
77                           (PickleTest, unittest.TestCase),
78                           {'proto': proto})
79
80if __name__ == "__main__":
81    unittest.main()
82