• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1"""
2A testcase which accesses *values* in a dll.
3"""
4
5import _imp
6import importlib.util
7import unittest
8import sys
9from ctypes import *
10from test.support import import_helper
11
12import _ctypes_test
13
14class ValuesTestCase(unittest.TestCase):
15
16    def test_an_integer(self):
17        # This test checks and changes an integer stored inside the
18        # _ctypes_test dll/shared lib.
19        ctdll = CDLL(_ctypes_test.__file__)
20        an_integer = c_int.in_dll(ctdll, "an_integer")
21        x = an_integer.value
22        self.assertEqual(x, ctdll.get_an_integer())
23        an_integer.value *= 2
24        self.assertEqual(x*2, ctdll.get_an_integer())
25        # To avoid test failures when this test is repeated several
26        # times the original value must be restored
27        an_integer.value = x
28        self.assertEqual(x, ctdll.get_an_integer())
29
30    def test_undefined(self):
31        ctdll = CDLL(_ctypes_test.__file__)
32        self.assertRaises(ValueError, c_int.in_dll, ctdll, "Undefined_Symbol")
33
34class PythonValuesTestCase(unittest.TestCase):
35    """This test only works when python itself is a dll/shared library"""
36
37    def test_optimizeflag(self):
38        # This test accesses the Py_OptimizeFlag integer, which is
39        # exported by the Python dll and should match the sys.flags value
40
41        opt = c_int.in_dll(pythonapi, "Py_OptimizeFlag").value
42        self.assertEqual(opt, sys.flags.optimize)
43
44    def test_frozentable(self):
45        # Python exports a PyImport_FrozenModules symbol. This is a
46        # pointer to an array of struct _frozen entries.  The end of the
47        # array is marked by an entry containing a NULL name and zero
48        # size.
49
50        # In standard Python, this table contains a __hello__
51        # module, and a __phello__ package containing a spam
52        # module.
53        class struct_frozen(Structure):
54            _fields_ = [("name", c_char_p),
55                        ("code", POINTER(c_ubyte)),
56                        ("size", c_int),
57                        ("is_package", c_int),
58                        ("get_code", POINTER(c_ubyte)),  # Function ptr
59                        ]
60        FrozenTable = POINTER(struct_frozen)
61
62        modules = []
63        for group in ["Bootstrap", "Stdlib", "Test"]:
64            ft = FrozenTable.in_dll(pythonapi, f"_PyImport_Frozen{group}")
65            # ft is a pointer to the struct_frozen entries:
66            for entry in ft:
67                # This is dangerous. We *can* iterate over a pointer, but
68                # the loop will not terminate (maybe with an access
69                # violation;-) because the pointer instance has no size.
70                if entry.name is None:
71                    break
72                modname = entry.name.decode("ascii")
73                modules.append(modname)
74                with self.subTest(modname):
75                    if entry.size != 0:
76                        # Do a sanity check on entry.size and entry.code.
77                        self.assertGreater(abs(entry.size), 10)
78                        self.assertTrue([entry.code[i] for i in range(abs(entry.size))])
79                    # Check the module's package-ness.
80                    with import_helper.frozen_modules():
81                        spec = importlib.util.find_spec(modname)
82                    if entry.is_package:
83                        # It's a package.
84                        self.assertIsNotNone(spec.submodule_search_locations)
85                    else:
86                        self.assertIsNone(spec.submodule_search_locations)
87
88        with import_helper.frozen_modules():
89            expected = _imp._frozen_module_names()
90        self.maxDiff = None
91        self.assertEqual(modules, expected,
92                         "_PyImport_FrozenBootstrap example "
93                         "in Doc/library/ctypes.rst may be out of date")
94
95        from ctypes import _pointer_type_cache
96        del _pointer_type_cache[struct_frozen]
97
98    def test_undefined(self):
99        self.assertRaises(ValueError, c_int.in_dll, pythonapi,
100                          "Undefined_Symbol")
101
102if __name__ == '__main__':
103    unittest.main()
104