diff options
Diffstat (limited to 'python/macholib/macholib_tests')
-rw-r--r-- | python/macholib/macholib_tests/__init__.py | 1 | ||||
-rw-r--r-- | python/macholib/macholib_tests/binaries/src/build.py | 22 | ||||
-rw-r--r-- | python/macholib/macholib_tests/test_MachO.py | 15 | ||||
-rw-r--r-- | python/macholib/macholib_tests/test_MachOGraph.py | 15 | ||||
-rw-r--r-- | python/macholib/macholib_tests/test_MachOStandalone.py | 15 | ||||
-rw-r--r-- | python/macholib/macholib_tests/test_SymbolTable.py | 15 | ||||
-rw-r--r-- | python/macholib/macholib_tests/test_command_line.py | 147 | ||||
-rw-r--r-- | python/macholib/macholib_tests/test_dyld.py | 450 | ||||
-rw-r--r-- | python/macholib/macholib_tests/test_dylib.py | 38 | ||||
-rw-r--r-- | python/macholib/macholib_tests/test_framework.py | 88 | ||||
-rw-r--r-- | python/macholib/macholib_tests/test_itergraphreport.py | 15 | ||||
-rw-r--r-- | python/macholib/macholib_tests/test_mach_o.py | 21 | ||||
-rw-r--r-- | python/macholib/macholib_tests/test_ptypes.py | 191 |
13 files changed, 1033 insertions, 0 deletions
diff --git a/python/macholib/macholib_tests/__init__.py b/python/macholib/macholib_tests/__init__.py new file mode 100644 index 0000000000..b5fe939b42 --- /dev/null +++ b/python/macholib/macholib_tests/__init__.py @@ -0,0 +1 @@ +""" macholib_tests package """ diff --git a/python/macholib/macholib_tests/binaries/src/build.py b/python/macholib/macholib_tests/binaries/src/build.py new file mode 100644 index 0000000000..e2a179c783 --- /dev/null +++ b/python/macholib/macholib_tests/binaries/src/build.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +import os, sys + + +class Builder (object): + def __init__(self, args): + self.output_dir = args[1] + + + def run(self): + for nm in dir(type(self)): + if nm.startswith('build_'): + getattr(self, nm)() + + def build_executable(self): + print "Building plain executable" + pass + + +builder = Builder(sys.argv) +builder.run() diff --git a/python/macholib/macholib_tests/test_MachO.py b/python/macholib/macholib_tests/test_MachO.py new file mode 100644 index 0000000000..730007e12f --- /dev/null +++ b/python/macholib/macholib_tests/test_MachO.py @@ -0,0 +1,15 @@ +from macholib import MachO + +import sys +if sys.version_info[:2] <= (2,6): + import unittest2 as unittest +else: + import unittest + +class TestMachO (unittest.TestCase): + @unittest.expectedFailure + def test_missing(self): + self.fail("tests are missing") + +if __name__ == "__main__": + unittest.main() diff --git a/python/macholib/macholib_tests/test_MachOGraph.py b/python/macholib/macholib_tests/test_MachOGraph.py new file mode 100644 index 0000000000..3f8e4ea19a --- /dev/null +++ b/python/macholib/macholib_tests/test_MachOGraph.py @@ -0,0 +1,15 @@ +from macholib import MachOGraph + +import sys +if sys.version_info[:2] <= (2,6): + import unittest2 as unittest +else: + import unittest + +class TestMachOGraph (unittest.TestCase): + @unittest.expectedFailure + def test_missing(self): + self.fail("tests are missing") + +if __name__ == "__main__": + unittest.main() diff --git a/python/macholib/macholib_tests/test_MachOStandalone.py b/python/macholib/macholib_tests/test_MachOStandalone.py new file mode 100644 index 0000000000..aa431e517f --- /dev/null +++ b/python/macholib/macholib_tests/test_MachOStandalone.py @@ -0,0 +1,15 @@ +from macholib import MachOStandalone + +import sys +if sys.version_info[:2] <= (2,6): + import unittest2 as unittest +else: + import unittest + +class TestMachOStandalone (unittest.TestCase): + @unittest.expectedFailure + def test_missing(self): + self.fail("tests are missing") + +if __name__ == "__main__": + unittest.main() diff --git a/python/macholib/macholib_tests/test_SymbolTable.py b/python/macholib/macholib_tests/test_SymbolTable.py new file mode 100644 index 0000000000..8970ca0a98 --- /dev/null +++ b/python/macholib/macholib_tests/test_SymbolTable.py @@ -0,0 +1,15 @@ +from macholib import SymbolTable + +import sys +if sys.version_info[:2] <= (2,6): + import unittest2 as unittest +else: + import unittest + +class TestSymbolTable (unittest.TestCase): + @unittest.expectedFailure + def test_missing(self): + self.fail("tests are missing") + +if __name__ == "__main__": + unittest.main() diff --git a/python/macholib/macholib_tests/test_command_line.py b/python/macholib/macholib_tests/test_command_line.py new file mode 100644 index 0000000000..a9cfd6f10a --- /dev/null +++ b/python/macholib/macholib_tests/test_command_line.py @@ -0,0 +1,147 @@ +from macholib import macho_dump +from macholib import macho_find +from macholib import _cmdline +from macholib import util + +import sys +import shutil +import os + +if sys.version_info[:2] <= (2,6): + import unittest2 as unittest +else: + import unittest + +try: + from StringIO import StringIO +except ImportError: + from io import StringIO + +class TestCmdLine (unittest.TestCase): + + # This test is no longer valid: + def no_test_main_is_shared(self): + self.assertTrue(macho_dump.main is _cmdline.main) + self.assertTrue(macho_find.main is _cmdline.main) + + def test_check_file(self): + record = [] + def record_cb(fp, path): + record.append((fp, path)) + + self.assertEqual(_cmdline.check_file(sys.stdout, '/bin/sh', record_cb), 0) + self.assertEqual(record, [(sys.stdout, '/bin/sh')]) + + saved_stderr = sys.stderr + saved_argv = sys.argv + try: + sys.stderr = StringIO() + sys.argv = ['macho_test'] + + record[:] = [] + self.assertEqual(_cmdline.check_file(sys.stdout, '/bin/no-shell', record_cb), 1) + self.assertEqual(record, []) + self.assertEqual(sys.stderr.getvalue(), "macho_test: /bin/no-shell: No such file or directory\n") + self.assertEqual(record, []) + + shutil.copy('/bin/sh', 'test.exec') + os.chmod('test.exec', 0) + + sys.stderr = StringIO() + self.assertEqual(_cmdline.check_file(sys.stdout, 'test.exec', record_cb), 1) + self.assertEqual(record, []) + self.assertEqual(sys.stderr.getvalue(), "macho_test: test.exec: [Errno 13] Permission denied: 'test.exec'\n") + self.assertEqual(record, []) + + + finally: + sys.stderr = sys.stderr + sys.argv = saved_argv + if os.path.exists('test.exec'): + os.unlink('test.exec') + + def test_shared_main(self): + + saved_stderr = sys.stderr + saved_argv = sys.argv + try: + sys.stderr = StringIO() + + sys.argv = ['macho_tool'] + + self.assertEqual(_cmdline.main(lambda *args: None), 1) + self.assertEqual(sys.stderr.getvalue(), 'Usage: macho_tool filename...\n') + + names = [] + def record_names(fp, name): + self.assertEqual(fp, sys.stdout) + names.append(name) + + + sys.stderr = StringIO() + sys.argv = ['macho_tool', '/bin/sh'] + self.assertEqual(_cmdline.main(record_names), 0) + self.assertEqual(sys.stderr.getvalue(), '') + self.assertEqual(names, ['/bin/sh']) + + names = [] + sys.stderr = StringIO() + sys.argv = ['macho_tool', '/bin/sh', '/bin/ls'] + self.assertEqual(_cmdline.main(record_names), 0) + self.assertEqual(sys.stderr.getvalue(), '') + self.assertEqual(names, ['/bin/sh', '/bin/ls']) + + names = [] + sys.stderr = StringIO() + sys.argv = ['macho_tool', '/bin'] + self.assertEqual(_cmdline.main(record_names), 0) + self.assertEqual(sys.stderr.getvalue(), '') + names.sort() + dn = '/bin' + real_names = [ + os.path.join(dn, fn) for fn in os.listdir(dn) + if util.is_platform_file(os.path.join(dn, fn)) ] + real_names.sort() + + self.assertEqual(names, real_names) + + finally: + sys.stderr = saved_stderr + sys.argv = saved_argv + + def test_macho_find(self): + fp = StringIO() + macho_find.print_file(fp, "file1") + macho_find.print_file(fp, "file2") + self.assertEqual(fp.getvalue(), "file1\nfile2\n") + + def test_macho_dump(self): + fp = StringIO() + macho_dump.print_file(fp, "/bin/sh") + lines = fp.getvalue().splitlines() + + self.assertEqual(lines[0], "/bin/sh") + self.assertTrue(len(lines) > 3) + + self.assertEqual(lines[-1], '') + del lines[-1] + + idx = 1 + while idx < len(lines): + self.assertTrue(lines[idx].startswith(' [MachOHeader endian')) + idx+=1 + + lc = 0 + while idx < len(lines): + if not lines[idx].startswith('\t'): + break + + lc +=1 + self.assertTrue(os.path.exists(lines[idx].lstrip())) + idx += 1 + + self.assertTrue(lc > 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/python/macholib/macholib_tests/test_dyld.py b/python/macholib/macholib_tests/test_dyld.py new file mode 100644 index 0000000000..7b41758d96 --- /dev/null +++ b/python/macholib/macholib_tests/test_dyld.py @@ -0,0 +1,450 @@ +from macholib import dyld + +import sys +import os +import functools + +if sys.version_info[:2] <= (2,6): + import unittest2 as unittest +else: + import unittest + +class DyldPatcher (object): + def __init__(self): + self.calls = [] + self.patched = {} + + def clear_calls(self): + self.calls = [] + + def cleanup(self): + for name in self.patched: + setattr(dyld, name, self.patched[name]) + + def log_calls(self, name): + if name in self.patched: + return + + self.patched[name] = getattr(dyld, name) + + + @functools.wraps(self.patched[name]) + def wrapper(*args, **kwds): + self.calls.append((name, args, kwds)) + return self.patched[name](*args, **kwds) + + setattr(dyld, name, wrapper) + + +class TestDyld (unittest.TestCase): + if not hasattr(unittest.TestCase, 'assertIsInstance'): + def assertIsInstance(self, value, types, message=None): + self.assertTrue(isinstance(value, types), + message or "%r is not an instance of %r"%(value, types)) + + def setUp(self): + self._environ = os.environ + os.environ = dict([(k, os.environ[k]) for k in os.environ if 'DYLD' not in k]) + self._dyld_env = dyld._dyld_env + self._dyld_image_suffix = dyld.dyld_image_suffix + + def tearDown(self): + dyld._dyld_env = self._dyld_env + dyld.dyld_image_suffix = self._dyld_image_suffix + os.environ = self._environ + + if sys.version_info[0] == 2: + def test_ensure_utf8(self): + self.assertEqual(dyld._ensure_utf8("hello"), "hello") + self.assertEqual(dyld._ensure_utf8("hello".decode('utf-8')), "hello") + self.assertEqual(dyld._ensure_utf8(None), None) + + else: + def test_ensure_utf8(self): + self.assertEqual(dyld._ensure_utf8("hello"), "hello") + self.assertEqual(dyld._ensure_utf8(None), None) + self.assertRaises(ValueError, dyld._ensure_utf8, b"hello") + + def test__dyld_env(self): + new = os.environ + + self.assertEqual(dyld._dyld_env(None, 'DYLD_FOO'), []) + self.assertEqual(dyld._dyld_env({'DYLD_FOO':'bar'}, 'DYLD_FOO'), ['bar']) + self.assertEqual(dyld._dyld_env({'DYLD_FOO':'bar:baz'}, 'DYLD_FOO'), ['bar', 'baz']) + self.assertEqual(dyld._dyld_env({}, 'DYLD_FOO'), []) + self.assertEqual(dyld._dyld_env({'DYLD_FOO':''}, 'DYLD_FOO'), []) + os.environ['DYLD_FOO'] = 'foobar' + self.assertEqual(dyld._dyld_env(None, 'DYLD_FOO'), ['foobar']) + os.environ['DYLD_FOO'] = 'foobar:nowhere' + self.assertEqual(dyld._dyld_env(None, 'DYLD_FOO'), ['foobar', 'nowhere']) + self.assertEqual(dyld._dyld_env({'DYLD_FOO':'bar'}, 'DYLD_FOO'), ['bar']) + self.assertEqual(dyld._dyld_env({}, 'DYLD_FOO'), []) + + + self.assertEqual(dyld.dyld_image_suffix(), None) + self.assertEqual(dyld.dyld_image_suffix(None), None) + self.assertEqual(dyld.dyld_image_suffix({'DYLD_IMAGE_SUFFIX':'bar'}), 'bar') + os.environ['DYLD_IMAGE_SUFFIX'] = 'foobar' + self.assertEqual(dyld.dyld_image_suffix(), 'foobar') + self.assertEqual(dyld.dyld_image_suffix(None), 'foobar') + + def test_dyld_helpers(self): + record = [] + def fake__dyld_env(env, key): + record.append((env, key)) + return ['hello'] + + dyld._dyld_env = fake__dyld_env + self.assertEqual(dyld.dyld_framework_path(), ['hello']) + self.assertEqual(dyld.dyld_framework_path({}), ['hello']) + + self.assertEqual(dyld.dyld_library_path(), ['hello']) + self.assertEqual(dyld.dyld_library_path({}), ['hello']) + + self.assertEqual(dyld.dyld_fallback_framework_path(), ['hello']) + self.assertEqual(dyld.dyld_fallback_framework_path({}), ['hello']) + + self.assertEqual(dyld.dyld_fallback_library_path(), ['hello']) + self.assertEqual(dyld.dyld_fallback_library_path({}), ['hello']) + + self.assertEqual(record, [ + (None, 'DYLD_FRAMEWORK_PATH'), + ({}, 'DYLD_FRAMEWORK_PATH'), + (None, 'DYLD_LIBRARY_PATH'), + ({}, 'DYLD_LIBRARY_PATH'), + (None, 'DYLD_FALLBACK_FRAMEWORK_PATH'), + ({}, 'DYLD_FALLBACK_FRAMEWORK_PATH'), + (None, 'DYLD_FALLBACK_LIBRARY_PATH'), + ({}, 'DYLD_FALLBACK_LIBRARY_PATH'), + ]) + + def test_dyld_suffix_search(self): + envs = [object()] + def fake_suffix(env): + envs[0] = env + return None + dyld.dyld_image_suffix = fake_suffix + + iterator = [ + '/usr/lib/foo', + '/usr/lib/foo.dylib', + ] + result = dyld.dyld_image_suffix_search(iter(iterator)) + self.assertEqual(list(result), iterator) + self.assertEqual(envs[0], None) + + result = dyld.dyld_image_suffix_search(iter(iterator), {}) + self.assertEqual(list(result), iterator) + self.assertEqual(envs[0], {}) + + envs = [object()] + def fake_suffix(env): + envs[0] = env + return '_profile' + dyld.dyld_image_suffix = fake_suffix + + iterator = [ + '/usr/lib/foo', + '/usr/lib/foo.dylib', + ] + result = dyld.dyld_image_suffix_search(iter(iterator)) + self.assertEqual(list(result), [ + '/usr/lib/foo_profile', + '/usr/lib/foo', + '/usr/lib/foo_profile.dylib', + '/usr/lib/foo.dylib', + ]) + self.assertEqual(envs[0], None) + + result = dyld.dyld_image_suffix_search(iter(iterator), {}) + self.assertEqual(list(result), [ + '/usr/lib/foo_profile', + '/usr/lib/foo', + '/usr/lib/foo_profile.dylib', + '/usr/lib/foo.dylib', + ]) + self.assertEqual(envs[0], {}) + + def test_override_search(self): + os.environ['DYLD_FRAMEWORK_PATH'] = '' + os.environ['DYLD_LIBRARY_PATH'] = '' + + self.assertEqual( + list(dyld.dyld_override_search("foo.dyld", None)), []) + self.assertEqual( + list(dyld.dyld_override_search("/usr/lib/libfoo.dyld", None)), []) + self.assertEqual( + list(dyld.dyld_override_search("/Library/Frameworks/Python.framework/Versions/Current/Python", None)), []) + + + os.environ['DYLD_FRAMEWORK_PATH'] = '/Foo/Frameworks:/Bar/Frameworks' + os.environ['DYLD_LIBRARY_PATH'] = '' + self.assertEqual( + list(dyld.dyld_override_search("foo.dyld", None)), []) + self.assertEqual( + list(dyld.dyld_override_search("/usr/lib/libfoo.dyld", None)), []) + self.assertEqual( + list(dyld.dyld_override_search("/Library/Frameworks/Python.framework/Versions/Current/Python", None)), [ + '/Foo/Frameworks/Python.framework/Versions/Current/Python', + '/Bar/Frameworks/Python.framework/Versions/Current/Python', + ]) + + os.environ['DYLD_FRAMEWORK_PATH'] = '' + os.environ['DYLD_LIBRARY_PATH'] = '/local/lib:/remote/lib' + self.assertEqual( + list(dyld.dyld_override_search("foo.dyld", None)), [ + '/local/lib/foo.dyld', + '/remote/lib/foo.dyld', + ]) + self.assertEqual( + list(dyld.dyld_override_search("/usr/lib/libfoo.dyld", None)), [ + '/local/lib/libfoo.dyld', + '/remote/lib/libfoo.dyld', + ]) + self.assertEqual( + list(dyld.dyld_override_search("/Library/Frameworks/Python.framework/Versions/Current/Python", None)), [ + '/local/lib/Python', + '/remote/lib/Python', + ]) + + os.environ['DYLD_FRAMEWORK_PATH'] = '/Foo/Frameworks:/Bar/Frameworks' + os.environ['DYLD_LIBRARY_PATH'] = '/local/lib:/remote/lib' + self.assertEqual( + list(dyld.dyld_override_search("foo.dyld", None)), [ + '/local/lib/foo.dyld', + '/remote/lib/foo.dyld', + ]) + self.assertEqual( + list(dyld.dyld_override_search("/usr/lib/libfoo.dyld", None)), [ + '/local/lib/libfoo.dyld', + '/remote/lib/libfoo.dyld', + ]) + self.assertEqual( + list(dyld.dyld_override_search("/Library/Frameworks/Python.framework/Versions/Current/Python", None)), [ + '/Foo/Frameworks/Python.framework/Versions/Current/Python', + '/Bar/Frameworks/Python.framework/Versions/Current/Python', + '/local/lib/Python', + '/remote/lib/Python', + ]) + + def test_executable_path_search(self): + self.assertEqual(list(dyld.dyld_executable_path_search("/usr/lib/foo.dyld", "/usr/bin")), []) + self.assertEqual( + list(dyld.dyld_executable_path_search("@executable_path/foo.dyld", "/usr/bin")), + ['/usr/bin/foo.dyld']) + self.assertEqual( + list(dyld.dyld_executable_path_search("@executable_path/../../lib/foo.dyld", "/usr/bin")), + ['/usr/bin/../../lib/foo.dyld']) + + def test_default_search(self): + self.assertEqual( + list(dyld.dyld_default_search('/usr/lib/mylib.dylib', None)), [ + '/usr/lib/mylib.dylib', + os.path.join(os.path.expanduser('~/lib'), 'mylib.dylib'), + '/usr/local/lib/mylib.dylib', + '/lib/mylib.dylib', + '/usr/lib/mylib.dylib', + + ]) + + self.assertEqual( + list(dyld.dyld_default_search('/Library/Frameworks/Python.framework/Versions/2.7/Python', None)), [ + '/Library/Frameworks/Python.framework/Versions/2.7/Python', + os.path.join(os.path.expanduser('~/Library/Frameworks'), 'Python.framework/Versions/2.7/Python'), + '/Library/Frameworks/Python.framework/Versions/2.7/Python', + '/Network/Library/Frameworks/Python.framework/Versions/2.7/Python', + '/System/Library/Frameworks/Python.framework/Versions/2.7/Python', + os.path.join(os.path.expanduser('~/lib'), 'Python'), + '/usr/local/lib/Python', + '/lib/Python', + '/usr/lib/Python', + ]) + + + + + os.environ['DYLD_FALLBACK_LIBRARY_PATH'] = '/local/lib:/network/lib' + os.environ['DYLD_FALLBACK_FRAMEWORK_PATH'] = '' + + self.assertEqual( + list(dyld.dyld_default_search('/usr/lib/mylib.dylib', None)), [ + '/usr/lib/mylib.dylib', + '/local/lib/mylib.dylib', + '/network/lib/mylib.dylib', + ]) + + + self.assertEqual( + list(dyld.dyld_default_search('/Library/Frameworks/Python.framework/Versions/2.7/Python', None)), [ + '/Library/Frameworks/Python.framework/Versions/2.7/Python', + os.path.join(os.path.expanduser('~/Library/Frameworks'), 'Python.framework/Versions/2.7/Python'), + '/Library/Frameworks/Python.framework/Versions/2.7/Python', + '/Network/Library/Frameworks/Python.framework/Versions/2.7/Python', + '/System/Library/Frameworks/Python.framework/Versions/2.7/Python', + '/local/lib/Python', + '/network/lib/Python', + ]) + + + os.environ['DYLD_FALLBACK_LIBRARY_PATH'] = '' + os.environ['DYLD_FALLBACK_FRAMEWORK_PATH'] = '/MyFrameworks:/OtherFrameworks' + + + self.assertEqual( + list(dyld.dyld_default_search('/usr/lib/mylib.dylib', None)), [ + '/usr/lib/mylib.dylib', + os.path.join(os.path.expanduser('~/lib'), 'mylib.dylib'), + '/usr/local/lib/mylib.dylib', + '/lib/mylib.dylib', + '/usr/lib/mylib.dylib', + + ]) + + self.assertEqual( + list(dyld.dyld_default_search('/Library/Frameworks/Python.framework/Versions/2.7/Python', None)), [ + '/Library/Frameworks/Python.framework/Versions/2.7/Python', + '/MyFrameworks/Python.framework/Versions/2.7/Python', + '/OtherFrameworks/Python.framework/Versions/2.7/Python', + os.path.join(os.path.expanduser('~/lib'), 'Python'), + '/usr/local/lib/Python', + '/lib/Python', + '/usr/lib/Python', + ]) + + os.environ['DYLD_FALLBACK_LIBRARY_PATH'] = '/local/lib:/network/lib' + os.environ['DYLD_FALLBACK_FRAMEWORK_PATH'] = '/MyFrameworks:/OtherFrameworks' + + + self.assertEqual( + list(dyld.dyld_default_search('/usr/lib/mylib.dylib', None)), [ + '/usr/lib/mylib.dylib', + '/local/lib/mylib.dylib', + '/network/lib/mylib.dylib', + + ]) + + self.assertEqual( + list(dyld.dyld_default_search('/Library/Frameworks/Python.framework/Versions/2.7/Python', None)), [ + '/Library/Frameworks/Python.framework/Versions/2.7/Python', + '/MyFrameworks/Python.framework/Versions/2.7/Python', + '/OtherFrameworks/Python.framework/Versions/2.7/Python', + '/local/lib/Python', + '/network/lib/Python', + ]) + + def test_dyld_find(self): + result = dyld.dyld_find('/usr/lib/libSystem.dylib') + self.assertEqual(result, '/usr/lib/libSystem.dylib') + self.assertIsInstance(result, str) # bytes on 2.x, unicode on 3.x + + result = dyld.dyld_find(b'/usr/lib/libSystem.dylib'.decode('ascii')) + self.assertEqual(result, '/usr/lib/libSystem.dylib') + self.assertIsInstance(result, str) # bytes on 2.x, unicode on 3.x + + patcher = DyldPatcher() + try: + patcher.log_calls('dyld_image_suffix_search') + patcher.log_calls('dyld_override_search') + patcher.log_calls('dyld_executable_path_search') + patcher.log_calls('dyld_default_search') + + result = dyld.dyld_find('/usr/lib/libSystem.dylib') + self.assertEqual(patcher.calls[:-1], [ + ('dyld_override_search', ('/usr/lib/libSystem.dylib', None), {}), + ('dyld_executable_path_search', ('/usr/lib/libSystem.dylib', None), {}), + ('dyld_default_search', ('/usr/lib/libSystem.dylib', None), {}), + ]) + self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search') + patcher.clear_calls() + + result = dyld.dyld_find('/usr/lib/libSystem.dylib', env=None) + self.assertEqual(patcher.calls[:-1], [ + ('dyld_override_search', ('/usr/lib/libSystem.dylib', None), {}), + ('dyld_executable_path_search', ('/usr/lib/libSystem.dylib', None), {}), + ('dyld_default_search', ('/usr/lib/libSystem.dylib', None), {}), + ]) + self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search') + patcher.clear_calls() + + result = dyld.dyld_find('/usr/lib/libSystem.dylib', env={}) + self.assertEqual(patcher.calls[:-1], [ + ('dyld_override_search', ('/usr/lib/libSystem.dylib', {}), {}), + ('dyld_executable_path_search', ('/usr/lib/libSystem.dylib', None), {}), + ('dyld_default_search', ('/usr/lib/libSystem.dylib', {}), {}), + ]) + self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search') + patcher.clear_calls() + + result = dyld.dyld_find('/usr/lib/libSystem.dylib', executable_path="/opt/py2app/bin", env={}) + self.assertEqual(patcher.calls[:-1], [ + ('dyld_override_search', ('/usr/lib/libSystem.dylib', {}), {}), + ('dyld_executable_path_search', ('/usr/lib/libSystem.dylib', "/opt/py2app/bin"), {}), + ('dyld_default_search', ('/usr/lib/libSystem.dylib', {}), {}), + ]) + self.assertEqual(patcher.calls[-1][0], 'dyld_image_suffix_search') + patcher.clear_calls() + + finally: + patcher.cleanup() + + def test_framework_find(self): + result = dyld.framework_find('/System/Library/Frameworks/Cocoa.framework/Versions/Current/Cocoa') + self.assertEqual(result, '/System/Library/Frameworks/Cocoa.framework/Versions/Current/Cocoa') + self.assertIsInstance(result, str) # bytes on 2.x, unicode on 3.x + + result = dyld.framework_find(b'/System/Library/Frameworks/Cocoa.framework/Versions/Current/Cocoa'.decode('latin1')) + self.assertEqual(result, '/System/Library/Frameworks/Cocoa.framework/Versions/Current/Cocoa') + self.assertIsInstance(result, str) # bytes on 2.x, unicode on 3.x + + result = dyld.framework_find('Cocoa.framework') + self.assertEqual(result, '/System/Library/Frameworks/Cocoa.framework/Cocoa') + self.assertIsInstance(result, str) # bytes on 2.x, unicode on 3.x + + result = dyld.framework_find('Cocoa') + self.assertEqual(result, '/System/Library/Frameworks/Cocoa.framework/Cocoa') + self.assertIsInstance(result, str) # bytes on 2.x, unicode on 3.x + + patcher = DyldPatcher() + try: + patcher.log_calls('dyld_find') + + result = dyld.framework_find('/System/Library/Frameworks/Cocoa.framework/Versions/Current/Cocoa') + self.assertEqual(patcher.calls, [ + ('dyld_find', ('/System/Library/Frameworks/Cocoa.framework/Versions/Current/Cocoa',), + {'env':None, 'executable_path': None}), + ]) + patcher.clear_calls() + + result = dyld.framework_find('Cocoa') + self.assertEqual(patcher.calls, [ + ('dyld_find', ('Cocoa',), + {'env':None, 'executable_path': None}), + ('dyld_find', ('Cocoa.framework/Cocoa',), + {'env':None, 'executable_path': None}), + ]) + patcher.clear_calls() + + result = dyld.framework_find('Cocoa', '/my/sw/bin', {}) + self.assertEqual(patcher.calls, [ + ('dyld_find', ('Cocoa',), + {'env':{}, 'executable_path': '/my/sw/bin'}), + ('dyld_find', ('Cocoa.framework/Cocoa',), + {'env':{}, 'executable_path': '/my/sw/bin'}), + ]) + patcher.clear_calls() + + + finally: + patcher.cleanup() + + + + +class TestTrivialDyld (unittest.TestCase): + # Tests ported from the implementation file + def testBasic(self): + self.assertEqual(dyld.dyld_find('libSystem.dylib'), '/usr/lib/libSystem.dylib') + self.assertEqual(dyld.dyld_find('System.framework/System'), '/System/Library/Frameworks/System.framework/System') + +if __name__ == "__main__": + unittest.main() diff --git a/python/macholib/macholib_tests/test_dylib.py b/python/macholib/macholib_tests/test_dylib.py new file mode 100644 index 0000000000..dcbc453582 --- /dev/null +++ b/python/macholib/macholib_tests/test_dylib.py @@ -0,0 +1,38 @@ +from macholib import dylib + +import sys +if sys.version_info[:2] <= (2,6): + import unittest2 as unittest +else: + import unittest + +def d(location=None, name=None, shortname=None, version=None, suffix=None): + return dict( + location=location, + name=name, + shortname=shortname, + version=version, + suffix=suffix + ) + +class TestDylib (unittest.TestCase): + def testInvalid(self): + self.assertTrue(dylib.dylib_info('completely/invalid') is None) + self.assertTrue(dylib.dylib_info('completely/invalid_debug') is None) + + def testUnversioned(self): + self.assertEqual(dylib.dylib_info('P/Foo.dylib'), + d('P', 'Foo.dylib', 'Foo')) + self.assertEqual(dylib.dylib_info('P/Foo_debug.dylib'), + d('P', 'Foo_debug.dylib', 'Foo', suffix='debug')) + + def testVersioned(self): + self.assertEqual(dylib.dylib_info('P/Foo.A.dylib'), + d('P', 'Foo.A.dylib', 'Foo', 'A')) + self.assertEqual(dylib.dylib_info('P/Foo_debug.A.dylib'), + d('P', 'Foo_debug.A.dylib', 'Foo_debug', 'A')) + self.assertEqual(dylib.dylib_info('P/Foo.A_debug.dylib'), + d('P', 'Foo.A_debug.dylib', 'Foo', 'A', 'debug')) + +if __name__ == "__main__": + unittest.main() diff --git a/python/macholib/macholib_tests/test_framework.py b/python/macholib/macholib_tests/test_framework.py new file mode 100644 index 0000000000..8c123afd00 --- /dev/null +++ b/python/macholib/macholib_tests/test_framework.py @@ -0,0 +1,88 @@ +from macholib import framework + +import sys +if sys.version_info[:2] <= (2,6): + import unittest2 as unittest +else: + import unittest + + +class TestFramework (unittest.TestCase): + def test_framework(self): + self.assertEqual( + framework.framework_info('Location/Name.framework/Versions/SomeVersion/Name_Suffix'), + dict( + location='Location', + name='Name.framework/Versions/SomeVersion/Name_Suffix', + shortname='Name', + version='SomeVersion', + suffix='Suffix', + )) + self.assertEqual( + framework.framework_info('Location/Name.framework/Versions/SomeVersion/Name'), + dict( + location='Location', + name='Name.framework/Versions/SomeVersion/Name', + shortname='Name', + version='SomeVersion', + suffix=None, + )) + self.assertEqual( + framework.framework_info('Location/Name.framework/Name_Suffix'), + dict( + location='Location', + name='Name.framework/Name_Suffix', + shortname='Name', + version=None, + suffix='Suffix', + )) + self.assertEqual( + framework.framework_info('Location/Name.framework/Name'), + dict( + location='Location', + name='Name.framework/Name', + shortname='Name', + version=None, + suffix=None + )) + self.assertEqual( + framework.framework_info('Location/Name.framework.disabled/Name'), + None + ) + self.assertEqual( + framework.framework_info('Location/Name.framework/Versions/A/B/Name'), + None + ) + self.assertEqual( + framework.framework_info('Location/Name.framework/Versions/A'), + None + ) + self.assertEqual( + framework.framework_info('Location/Name.framework/Versions/A/Name/_debug'), + None + ) + + def test_interal_tests(self): + # Ported over from the source file + def d(location=None, name=None, shortname=None, version=None, suffix=None): + return dict( + location=location, + name=name, + shortname=shortname, + version=version, + suffix=suffix + ) + self.assertEqual(framework.framework_info('completely/invalid'), None) + self.assertEqual(framework.framework_info('completely/invalid/_debug'), None) + self.assertEqual(framework.framework_info('P/F.framework'), None) + self.assertEqual(framework.framework_info('P/F.framework/_debug'), None) + self.assertEqual(framework.framework_info('P/F.framework/F'), d('P', 'F.framework/F', 'F')) + self.assertEqual(framework.framework_info('P/F.framework/F_debug'), d('P', 'F.framework/F_debug', 'F', suffix='debug')) + self.assertEqual(framework.framework_info('P/F.framework/Versions'), None) + self.assertEqual(framework.framework_info('P/F.framework/Versions/A'), None) + self.assertEqual(framework.framework_info('P/F.framework/Versions/A/F'), d('P', 'F.framework/Versions/A/F', 'F', 'A')) + self.assertEqual(framework.framework_info('P/F.framework/Versions/A/F_debug'), d('P', 'F.framework/Versions/A/F_debug', 'F', 'A', 'debug')) + + +if __name__ == "__main__": + unittest.main() diff --git a/python/macholib/macholib_tests/test_itergraphreport.py b/python/macholib/macholib_tests/test_itergraphreport.py new file mode 100644 index 0000000000..f3e7c28a34 --- /dev/null +++ b/python/macholib/macholib_tests/test_itergraphreport.py @@ -0,0 +1,15 @@ +from macholib import itergraphreport + +import sys +if sys.version_info[:2] <= (2,6): + import unittest2 as unittest +else: + import unittest + +class TestIterGraphReport (unittest.TestCase): + @unittest.expectedFailure + def test_missing(self): + self.fail("tests are missing") + +if __name__ == "__main__": + unittest.main() diff --git a/python/macholib/macholib_tests/test_mach_o.py b/python/macholib/macholib_tests/test_mach_o.py new file mode 100644 index 0000000000..0fbcf04b2f --- /dev/null +++ b/python/macholib/macholib_tests/test_mach_o.py @@ -0,0 +1,21 @@ +from macholib import mach_o + +import sys +if sys.version_info[:2] <= (2,6): + import unittest2 as unittest +else: + import unittest + + +class TestMachO (unittest.TestCase): + # This module is just a set of struct definitions, + # not sure how to test those without replicating + # the code. + # + # The definitions will get exercised by the + # other tests, therefore testing is ignored + # for now. + pass + +if __name__ == "__main__": + unittest.main() diff --git a/python/macholib/macholib_tests/test_ptypes.py b/python/macholib/macholib_tests/test_ptypes.py new file mode 100644 index 0000000000..f221d37d32 --- /dev/null +++ b/python/macholib/macholib_tests/test_ptypes.py @@ -0,0 +1,191 @@ +from macholib import ptypes + +import unittest +import sys +if sys.version_info[:2] <= (2,6): + import unittest2 as unittest +else: + import unittest + +try: + from io import BytesIO +except ImportError: + from cStringIO import StringIO as BytesIO +import mmap + +try: + long +except NameError: + long = int + + +class TestPTypes (unittest.TestCase): + if not hasattr(unittest.TestCase, 'assertIsSubclass'): + def assertIsSubclass(self, class1, class2, message=None): + self.assertTrue(issubclass(class1, class2), + message or "%r is not a subclass of %r"%(class1, class2)) + + if not hasattr(unittest.TestCase, 'assertIsInstance'): + def assertIsInstance(self, value, types, message=None): + self.assertTrue(isinstance(value, types), + message or "%r is not an instance of %r"%(value, types)) + + def test_sizeof(self): + self.assertEqual(ptypes.sizeof(b"foobar"), 6) + + self.assertRaises(ValueError, ptypes.sizeof, []) + self.assertRaises(ValueError, ptypes.sizeof, {}) + self.assertRaises(ValueError, ptypes.sizeof, b"foo".decode('ascii')) + + class M (object): + pass + + m = M() + m._size_ = 42 + self.assertEqual(ptypes.sizeof(m), 42) + + + def verifyType(self, ptype, size, pytype, values): + self.assertEqual(ptypes.sizeof(ptype), size) + self.assertIsSubclass(ptype, pytype) + + for v in values: + pv = ptype(v) + packed = pv.to_str() + self.assertIsInstance(packed, bytes) + self.assertEqual(len(packed), size) + + unp = ptype.from_str(packed) + self.assertIsInstance(unp, ptype) + self.assertEqual(unp, pv) + + fp = BytesIO(packed) + unp = ptype.from_fileobj(fp) + fp.close() + self.assertIsInstance(unp, ptype) + self.assertEqual(unp, pv) + + fp = BytesIO() + pv.to_fileobj(fp) + data = fp.getvalue() + fp.close() + self.assertEqual(data, packed) + + mm = mmap.mmap(-1, size+20) + mm[:] = b'\x00' * (size+20) + pv.to_mmap(mm, 10) + + self.assertEqual(ptype.from_mmap(mm, 10), pv) + self.assertEqual(mm[:], (b'\x00'*10) + packed + (b'\x00'*10)) + + self.assertEqual(ptype.from_tuple((v,)), pv) + + def test_basic_types(self): + self.verifyType(ptypes.p_char, 1, bytes, [b'a', b'b']) + self.verifyType(ptypes.p_int8, 1, int, [1, 42, -4]) + self.verifyType(ptypes.p_uint8, 1, int, [1, 42, 253]) + + self.verifyType(ptypes.p_int16, 2, int, [1, 400, -10, -5000]) + self.verifyType(ptypes.p_uint16, 2, int, [1, 400, 65000]) + + self.verifyType(ptypes.p_int32, 4, int, [1, 400, 2**24, -10, -5000, -2**24]) + self.verifyType(ptypes.p_uint32, 4, long, [1, 400, 2*31+5, 65000]) + + self.verifyType(ptypes.p_int64, 8, long, [1, 400, 2**43, -10, -5000, -2**43]) + self.verifyType(ptypes.p_uint64, 8, long, [1, 400, 2*63+5, 65000]) + + self.verifyType(ptypes.p_float, 4, float, [1.0, 42.5]) + self.verifyType(ptypes.p_double, 8, float, [1.0, 42.5]) + + def test_basic_types_deprecated(self): + self.verifyType(ptypes.p_byte, 1, int, [1, 42, -4]) + self.verifyType(ptypes.p_ubyte, 1, int, [1, 42, 253]) + + self.verifyType(ptypes.p_short, 2, int, [1, 400, -10, -5000]) + self.verifyType(ptypes.p_ushort, 2, int, [1, 400, 65000]) + + self.verifyType(ptypes.p_int, 4, int, [1, 400, 2**24, -10, -5000, -2**24]) + self.verifyType(ptypes.p_uint, 4, long, [1, 400, 2*31+5, 65000]) + + self.verifyType(ptypes.p_long, 4, int, [1, 400, 2**24, -10, -5000, -2**24]) + self.verifyType(ptypes.p_ulong, 4, long, [1, 400, 2*31+5, 65000]) + + self.verifyType(ptypes.p_longlong, 8, long, [1, 400, 2**43, -10, -5000, -2**43]) + self.verifyType(ptypes.p_ulonglong, 8, long, [1, 400, 2*63+5, 65000]) + +class TestPTypesPrivate (unittest.TestCase): + # These are tests for functions that aren't part of the public + # API. + + def test_formatinfo(self): + self.assertEqual(ptypes._formatinfo(">b"), (1, 1)) + self.assertEqual(ptypes._formatinfo(">h"), (2, 1)) + self.assertEqual(ptypes._formatinfo(">HhL"), (8, 3)) + self.assertEqual(ptypes._formatinfo("<b"), (1, 1)) + self.assertEqual(ptypes._formatinfo("<h"), (2, 1)) + self.assertEqual(ptypes._formatinfo("<HhL"), (8, 3)) + + +class MyStructure (ptypes.Structure): + _fields_ = ( + ('foo', ptypes.p_int32), + ('bar', ptypes.p_uint8), + ) + +class MyFunStructure (ptypes.Structure): + _fields_ = ( + ('fun', ptypes.p_char), + ('mystruct', MyStructure), + ) + +class TestPTypesSimple (unittest.TestCase): + # Quick port of tests that used to be part of + # the macholib.ptypes source code + # + # Moving these in a structured manner to TestPTypes + # would be nice, but is not extremely important. + + def testBasic(self): + for endian in '><': + kw = dict(_endian_=endian) + MYSTRUCTURE = b'\x00\x11\x22\x33\xFF' + for fn, args in [ + ('from_str', (MYSTRUCTURE,)), + ('from_mmap', (MYSTRUCTURE, 0)), + ('from_fileobj', (BytesIO(MYSTRUCTURE),)), + ]: + myStructure = getattr(MyStructure, fn)(*args, **kw) + if endian == '>': + self.assertEqual(myStructure.foo, 0x00112233) + else: + self.assertEqual( myStructure.foo, 0x33221100) + self.assertEqual(myStructure.bar, 0xFF) + self.assertEqual(myStructure.to_str(), MYSTRUCTURE) + + MYFUNSTRUCTURE = b'!' + MYSTRUCTURE + for fn, args in [ + ('from_str', (MYFUNSTRUCTURE,)), + ('from_mmap', (MYFUNSTRUCTURE, 0)), + ('from_fileobj', (BytesIO(MYFUNSTRUCTURE),)), + ]: + myFunStructure = getattr(MyFunStructure, fn)(*args, **kw) + self.assertEqual(myFunStructure.mystruct, myStructure) + self.assertEqual(myFunStructure.fun, b'!', (myFunStructure.fun, b'!')) + self.assertEqual(myFunStructure.to_str(), MYFUNSTRUCTURE) + + sio = BytesIO() + myFunStructure.to_fileobj(sio) + self.assertEqual(sio.getvalue(), MYFUNSTRUCTURE) + + mm = mmap.mmap(-1, ptypes.sizeof(MyFunStructure) * 2) + mm[:] = b'\x00' * (ptypes.sizeof(MyFunStructure) * 2) + myFunStructure.to_mmap(mm, 0) + self.assertEqual(MyFunStructure.from_mmap(mm, 0, **kw), myFunStructure) + self.assertEqual(mm[:ptypes.sizeof(MyFunStructure)], MYFUNSTRUCTURE) + self.assertEqual(mm[ptypes.sizeof(MyFunStructure):], b'\x00' * ptypes.sizeof(MyFunStructure)) + myFunStructure.to_mmap(mm, ptypes.sizeof(MyFunStructure)) + self.assertEqual(mm[:], MYFUNSTRUCTURE + MYFUNSTRUCTURE) + self.assertEqual(MyFunStructure.from_mmap(mm, ptypes.sizeof(MyFunStructure), **kw), myFunStructure) + +if __name__ == "__main__": + unittest.main() |