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