• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import unittest
2import unittest.mock
3import os.path
4import sys
5import test.support
6from test.support import os_helper
7from ctypes import *
8from ctypes.util import find_library
9
10# On some systems, loading the OpenGL libraries needs the RTLD_GLOBAL mode.
11class Test_OpenGL_libs(unittest.TestCase):
12    @classmethod
13    def setUpClass(cls):
14        lib_gl = lib_glu = lib_gle = None
15        if sys.platform == "win32":
16            lib_gl = find_library("OpenGL32")
17            lib_glu = find_library("Glu32")
18        elif sys.platform == "darwin":
19            lib_gl = lib_glu = find_library("OpenGL")
20        else:
21            lib_gl = find_library("GL")
22            lib_glu = find_library("GLU")
23            lib_gle = find_library("gle")
24
25        ## print, for debugging
26        if test.support.verbose:
27            print("OpenGL libraries:")
28            for item in (("GL", lib_gl),
29                         ("GLU", lib_glu),
30                         ("gle", lib_gle)):
31                print("\t", item)
32
33        cls.gl = cls.glu = cls.gle = None
34        if lib_gl:
35            try:
36                cls.gl = CDLL(lib_gl, mode=RTLD_GLOBAL)
37            except OSError:
38                pass
39        if lib_glu:
40            try:
41                cls.glu = CDLL(lib_glu, RTLD_GLOBAL)
42            except OSError:
43                pass
44        if lib_gle:
45            try:
46                cls.gle = CDLL(lib_gle)
47            except OSError:
48                pass
49
50    @classmethod
51    def tearDownClass(cls):
52        cls.gl = cls.glu = cls.gle = None
53
54    def test_gl(self):
55        if self.gl is None:
56            self.skipTest('lib_gl not available')
57        self.gl.glClearIndex
58
59    def test_glu(self):
60        if self.glu is None:
61            self.skipTest('lib_glu not available')
62        self.glu.gluBeginCurve
63
64    def test_gle(self):
65        if self.gle is None:
66            self.skipTest('lib_gle not available')
67        self.gle.gleGetJoinStyle
68
69    def test_shell_injection(self):
70        result = find_library('; echo Hello shell > ' + os_helper.TESTFN)
71        self.assertFalse(os.path.lexists(os_helper.TESTFN))
72        self.assertIsNone(result)
73
74
75@unittest.skipUnless(sys.platform.startswith('linux'),
76                     'Test only valid for Linux')
77class FindLibraryLinux(unittest.TestCase):
78    def test_find_on_libpath(self):
79        import subprocess
80        import tempfile
81
82        try:
83            p = subprocess.Popen(['gcc', '--version'], stdout=subprocess.PIPE,
84                                 stderr=subprocess.DEVNULL)
85            out, _ = p.communicate()
86        except OSError:
87            raise unittest.SkipTest('gcc, needed for test, not available')
88        with tempfile.TemporaryDirectory() as d:
89            # create an empty temporary file
90            srcname = os.path.join(d, 'dummy.c')
91            libname = 'py_ctypes_test_dummy'
92            dstname = os.path.join(d, 'lib%s.so' % libname)
93            with open(srcname, 'wb') as f:
94                pass
95            self.assertTrue(os.path.exists(srcname))
96            # compile the file to a shared library
97            cmd = ['gcc', '-o', dstname, '--shared',
98                   '-Wl,-soname,lib%s.so' % libname, srcname]
99            out = subprocess.check_output(cmd)
100            self.assertTrue(os.path.exists(dstname))
101            # now check that the .so can't be found (since not in
102            # LD_LIBRARY_PATH)
103            self.assertIsNone(find_library(libname))
104            # now add the location to LD_LIBRARY_PATH
105            with os_helper.EnvironmentVarGuard() as env:
106                KEY = 'LD_LIBRARY_PATH'
107                if KEY not in env:
108                    v = d
109                else:
110                    v = '%s:%s' % (env[KEY], d)
111                env.set(KEY, v)
112                # now check that the .so can be found (since in
113                # LD_LIBRARY_PATH)
114                self.assertEqual(find_library(libname), 'lib%s.so' % libname)
115
116    def test_find_library_with_gcc(self):
117        with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None):
118            self.assertNotEqual(find_library('c'), None)
119
120    def test_find_library_with_ld(self):
121        with unittest.mock.patch("ctypes.util._findSoname_ldconfig", lambda *args: None), \
122             unittest.mock.patch("ctypes.util._findLib_gcc", lambda *args: None):
123            self.assertNotEqual(find_library('c'), None)
124
125
126if __name__ == "__main__":
127    unittest.main()
128