""" Tests for install name utilities """ import os from os.path import (join as pjoin, exists, dirname, basename) import shutil from ..tools import (InstallNameError, get_install_names, set_install_name, get_install_id, get_rpaths, add_rpath, parse_install_name, set_install_id, get_environment_variable_paths) from ..tmpdirs import InTemporaryDirectory from .pytest_tools import (assert_raises, assert_equal) from .env_tools import TempDirWithoutEnvVars # External libs linked from test data LIBSTDCXX = '/usr/lib/libstdc++.6.dylib' LIBSYSTEMB = '/usr/lib/libSystem.B.dylib' EXT_LIBS = (LIBSTDCXX, LIBSYSTEMB) DATA_PATH = pjoin(dirname(__file__), 'data') LIBA = pjoin(DATA_PATH, 'liba.dylib') LIBB = pjoin(DATA_PATH, 'libb.dylib') LIBC = pjoin(DATA_PATH, 'libc.dylib') LIBA_STATIC = pjoin(DATA_PATH, 'liba.a') A_OBJECT = pjoin(DATA_PATH, 'a.o') TEST_LIB = pjoin(DATA_PATH, 'test-lib') ICO_FILE = pjoin(DATA_PATH, 'icon.ico') PY_FILE = pjoin(DATA_PATH, 'some_code.py') BIN_FILE = pjoin(DATA_PATH, 'binary_example.bin') def test_get_install_names(): # Test install name listing assert_equal(set(get_install_names(LIBA)), set(EXT_LIBS)) assert_equal(set(get_install_names(LIBB)), set(('liba.dylib',) + EXT_LIBS)) assert_equal(set(get_install_names(LIBC)), set(('liba.dylib', 'libb.dylib') + EXT_LIBS)) assert_equal(set(get_install_names(TEST_LIB)), set(('libc.dylib',) + EXT_LIBS)) # Non-object file returns empty tuple assert_equal(get_install_names(__file__), ()) # Static archive and object files returns empty tuple assert_equal(get_install_names(A_OBJECT), ()) assert_equal(get_install_names(LIBA_STATIC), ()) # ico file triggers another error message and should also return an empty tuple # noqa: E501 assert_equal(get_install_names(ICO_FILE), ()) # Python file (__file__ above may be a pyc file) assert_equal(get_install_names(PY_FILE), ()) # Binary file (in fact a truncated SAS file) assert_equal(get_install_names(BIN_FILE), ()) # Test when no read permission with InTemporaryDirectory(): shutil.copyfile(LIBA, 'test.dylib') assert_equal(set(get_install_names('test.dylib')), set(EXT_LIBS)) # No permissions, no found libs os.chmod('test.dylib', 0) assert_equal(get_install_names('test.dylib'), ()) def test_parse_install_name(): assert_equal(parse_install_name( "liba.dylib (compatibility version 0.0.0, current version 0.0.0)"), ("liba.dylib", "0.0.0", "0.0.0")) assert_equal(parse_install_name( " /usr/lib/libstdc++.6.dylib (compatibility version 1.0.0, " "current version 120.0.0)"), ("/usr/lib/libstdc++.6.dylib", "1.0.0", "120.0.0")) assert_equal(parse_install_name( "\t\t /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, " "current version 1197.1.1)"), ("/usr/lib/libSystem.B.dylib", "1.0.0", "1197.1.1")) def test_install_id(): # Test basic otool library listing assert_equal(get_install_id(LIBA), 'liba.dylib') assert_equal(get_install_id(LIBB), 'libb.dylib') assert_equal(get_install_id(LIBC), 'libc.dylib') assert_equal(get_install_id(TEST_LIB), None) # Non-object file returns None too assert_equal(get_install_id(__file__), None) assert_equal(get_install_id(ICO_FILE), None) def test_change_install_name(): # Test ability to change install names in library libb_names = get_install_names(LIBB) with InTemporaryDirectory() as tmpdir: libfoo = pjoin(tmpdir, 'libfoo.dylib') shutil.copy2(LIBB, libfoo) assert_equal(get_install_names(libfoo), libb_names) set_install_name(libfoo, 'liba.dylib', 'libbar.dylib') assert_equal(get_install_names(libfoo), ('libbar.dylib',) + libb_names[1:]) # If the name not found, raise an error assert_raises(InstallNameError, set_install_name, libfoo, 'liba.dylib', 'libpho.dylib') def test_set_install_id(): # Test ability to change install id in library liba_id = get_install_id(LIBA) with InTemporaryDirectory() as tmpdir: libfoo = pjoin(tmpdir, 'libfoo.dylib') shutil.copy2(LIBA, libfoo) assert_equal(get_install_id(libfoo), liba_id) set_install_id(libfoo, 'libbar.dylib') assert_equal(get_install_id(libfoo), 'libbar.dylib') # If no install id, raise error (unlike install_name_tool) assert_raises(InstallNameError, set_install_id, TEST_LIB, 'libbof.dylib') def test_get_rpaths(): # Test fetch of rpaths # Not dynamic libs, no rpaths for fname in (LIBB, A_OBJECT, LIBA_STATIC, ICO_FILE, PY_FILE, BIN_FILE): assert_equal(get_rpaths(fname), ()) def test_get_environment_variable_paths(): # Test that environment variable paths are fetched in a specific order with TempDirWithoutEnvVars('DYLD_FALLBACK_LIBRARY_PATH', 'DYLD_LIBRARY_PATH'): os.environ['DYLD_FALLBACK_LIBRARY_PATH'] = 'three' os.environ['DYLD_LIBRARY_PATH'] = 'two' assert_equal(get_environment_variable_paths(), ('two', 'three')) def test_add_rpath(): # Test adding to rpath with InTemporaryDirectory() as tmpdir: libfoo = pjoin(tmpdir, 'libfoo.dylib') shutil.copy2(LIBB, libfoo) assert_equal(get_rpaths(libfoo), ()) add_rpath(libfoo, '/a/path') assert_equal(get_rpaths(libfoo), ('/a/path',)) add_rpath(libfoo, '/another/path') assert_equal(get_rpaths(libfoo), ('/a/path', '/another/path')) def _copy_libs(lib_files, out_path): copied = [] if not exists(out_path): os.makedirs(out_path) for in_fname in lib_files: out_fname = pjoin(out_path, basename(in_fname)) shutil.copy2(in_fname, out_fname) copied.append(out_fname) return copied