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(unittest.TestCase):
18    def dumps(self, item):
19        return pickle.dumps(item)
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        pickle.dumps(c_char("x"))
71        # Issue 5049
72        pickle.dumps(c_wchar(u"x"))
73
74class PickleTest_1(PickleTest):
75    def dumps(self, item):
76        return pickle.dumps(item, 1)
77
78class PickleTest_2(PickleTest):
79    def dumps(self, item):
80        return pickle.dumps(item, 2)
81
82if __name__ == "__main__":
83    unittest.main()
84