summaryrefslogtreecommitdiff
path: root/python/macholib/macholib_tests
diff options
context:
space:
mode:
Diffstat (limited to 'python/macholib/macholib_tests')
-rw-r--r--python/macholib/macholib_tests/__init__.py1
-rw-r--r--python/macholib/macholib_tests/binaries/src/build.py22
-rw-r--r--python/macholib/macholib_tests/test_MachO.py15
-rw-r--r--python/macholib/macholib_tests/test_MachOGraph.py15
-rw-r--r--python/macholib/macholib_tests/test_MachOStandalone.py15
-rw-r--r--python/macholib/macholib_tests/test_SymbolTable.py15
-rw-r--r--python/macholib/macholib_tests/test_command_line.py147
-rw-r--r--python/macholib/macholib_tests/test_dyld.py450
-rw-r--r--python/macholib/macholib_tests/test_dylib.py38
-rw-r--r--python/macholib/macholib_tests/test_framework.py88
-rw-r--r--python/macholib/macholib_tests/test_itergraphreport.py15
-rw-r--r--python/macholib/macholib_tests/test_mach_o.py21
-rw-r--r--python/macholib/macholib_tests/test_ptypes.py191
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()