diff options
Diffstat (limited to 'lldb/packages/Python/lldbsuite/test/lldbtest.py')
-rw-r--r-- | lldb/packages/Python/lldbsuite/test/lldbtest.py | 277 |
1 files changed, 30 insertions, 247 deletions
diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 6847935034c..1f66df1f4b8 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -37,7 +37,6 @@ from __future__ import absolute_import # System modules import abc import collections -from distutils.version import LooseVersion import gc import glob import inspect @@ -60,11 +59,13 @@ import six import use_lldb_suite import lldb from . import configuration +from . import decorators from . import lldbplatformutil from . import lldbtest_config from . import lldbutil from . import test_categories from lldbsuite.support import encoded_file +from lldbsuite.support import funcutils from .result_formatter import EventBuilder @@ -440,43 +441,9 @@ def builder_module(): return __import__("builder_netbsd") return __import__("builder_" + sys.platform) -def does_function_require_self(func): - import inspect - func_argc = len(inspect.getargspec(func).args) - if func_argc == 0 or (getattr(func,'im_self',None) is not None) or (hasattr(func, '__self__')): - return False - else: - return True - -def check_expected_version(comparison, expected, actual): - def fn_leq(x,y): return x <= y - def fn_less(x,y): return x < y - def fn_geq(x,y): return x >= y - def fn_greater(x,y): return x > y - def fn_eq(x,y): return x == y - def fn_neq(x,y): return x != y - - op_lookup = { - "==": fn_eq, - "=": fn_eq, - "!=": fn_neq, - "<>": fn_neq, - ">": fn_greater, - "<": fn_less, - ">=": fn_geq, - "<=": fn_leq - } - expected_str = '.'.join([str(x) for x in expected]) - actual_str = '.'.join([str(x) for x in actual]) - - return op_lookup[comparison](LooseVersion(actual_str), LooseVersion(expected_str)) - # # Decorators for categorizing test cases. # -class DecorateMode: - Skip, Xfail = range(2) - from functools import wraps def skip_for_android(reason, api_levels, archs): @@ -504,7 +471,7 @@ def benchmarks_test(func): return "benchmarks test" # Mark this function as such to separate them from the regular tests. - result = skipTestIfFn(should_skip_benchmarks_test)(func) + result = decorators.skipTestIfFn(should_skip_benchmarks_test)(func) result.__benchmarks_test__ = True return result @@ -525,48 +492,19 @@ def debugserver_test(func): """Decorate the item as a debugserver test.""" def should_skip_debugserver_test(): return "debugserver tests" if configuration.dont_do_debugserver_test else None - return skipTestIfFn(should_skip_debugserver_test)(func) + return decorators.skipTestIfFn(should_skip_debugserver_test)(func) def llgs_test(func): """Decorate the item as a lldb-server test.""" def should_skip_llgs_tests(): return "llgs tests" if configuration.dont_do_llgs_test else None - return skipTestIfFn(should_skip_llgs_tests)(func) + return decorators.skipTestIfFn(should_skip_llgs_tests)(func) def not_remote_testsuite_ready(func): """Decorate the item as a test which is not ready yet for remote testsuite.""" def is_remote(): return "Not ready for remote testsuite" if lldb.remote_platform else None - return skipTestIfFn(is_remote)(func) - -def expectedFailure(expected_fn, bugnumber=None): - def expectedFailure_impl(func): - if isinstance(func, type) and issubclass(func, unittest2.TestCase): - raise Exception("Decorator can only be used to decorate a test method") - @wraps(func) - def wrapper(*args, **kwargs): - from unittest2 import case - self = args[0] - xfail_reason = expected_fn(self) - if xfail_reason is not None: - if configuration.results_formatter_object is not None: - # Mark this test as expected to fail. - configuration.results_formatter_object.handle_event( - EventBuilder.event_for_mark_test_expected_failure(self)) - xfail_func = unittest2.expectedFailure(func) - xfail_func(*args, **kwargs) - else: - func(*args, **kwargs) - return wrapper - # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows) - # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])). When called - # the first way, the first argument will be the actual function because decorators are - # weird like that. So this is basically a check that says "which syntax was the original - # function decorated with?" - if six.callable(bugnumber): - return expectedFailure_impl(bugnumber) - else: - return expectedFailure_impl + return decorators.skipTestIfFn(is_remote)(func) # You can also pass not_in(list) to reverse the sense of the test for the arguments that # are simple lists, namely oslist, compiler, and debug_info. @@ -574,19 +512,6 @@ def expectedFailure(expected_fn, bugnumber=None): def not_in(iterable): return lambda x : x not in iterable -def check_list_or_lambda(list_or_lambda, value): - if six.callable(list_or_lambda): - return list_or_lambda(value) - elif isinstance(list_or_lambda, list): - for item in list_or_lambda: - if value in item: - return True - return False - elif isinstance(list_or_lambda, str): - return value is None or value in list_or_lambda - else: - return list_or_lambda is None or value is None or list_or_lambda == value - def matchArchitectures(archs, actual_arch): retype = type(re.compile('hello, world')) list_passes = isinstance(archs, list) and actual_arch in archs @@ -595,41 +520,19 @@ def matchArchitectures(archs, actual_arch): return (list_passes or basestring_passes or regex_passes) -# provide a function to xfail on defined oslist, compiler version, and archs -# if none is specified for any argument, that argument won't be checked and thus means for all -# for example, -# @expectedFailureAll, xfail for all platform/compiler/arch, -# @expectedFailureAll(compiler='gcc'), xfail for gcc on all platform/architecture -# @expectedFailureAll(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), xfail for gcc>=4.9 on linux with i386 -def expectedFailureAll(bugnumber=None, - oslist=None, hostoslist=None, - compiler=None, compiler_version=None, - archs=None, triple=None, - debug_info=None, - swig_version=None, py_version=None, - remote=None): - return decorateTest(DecorateMode.Xfail, - bugnumber=bugnumber, - oslist=oslist, hostoslist=hostoslist, - compiler=compiler, compiler_version=compiler_version, - archs=archs, triple=triple, - debug_info=debug_info, - swig_version=swig_version, py_version=py_version, - remote=remote) - def expectedFailureDwarf(bugnumber=None): - return expectedFailureAll(bugnumber=bugnumber, debug_info="dwarf") + return decorators.expectedFailureAll(bugnumber=bugnumber, debug_info="dwarf") def expectedFailureDwo(bugnumber=None): - return expectedFailureAll(bugnumber=bugnumber, debug_info="dwo") + return decorators.expectedFailureAll(bugnumber=bugnumber, debug_info="dwo") def expectedFailureDsym(bugnumber=None): - return expectedFailureAll(bugnumber=bugnumber, debug_info="dsym") + return decorators.expectedFailureAll(bugnumber=bugnumber, debug_info="dsym") def expectedFailureCompiler(compiler, compiler_version=None, bugnumber=None): if compiler_version is None: compiler_version=['=', None] - return expectedFailureAll(bugnumber=bugnumber, compiler=compiler, compiler_version=compiler_version) + return decorators.expectedFailureAll(bugnumber=bugnumber, compiler=compiler, compiler_version=compiler_version) # to XFAIL a specific clang versions, try this # @expectedFailureClang('bugnumber', ['<=', '3.4']) @@ -643,7 +546,7 @@ def expectedFailureIcc(bugnumber=None): return expectedFailureCompiler('icc', None, bugnumber) def expectedFailureArch(arch, bugnumber=None): - return decorateTest(DecorateMode.Xfail, archs=arch, bugnumber=bugnumber) + return decorators.expectedFailureAll(archs=arch, bugnumber=bugnumber) def expectedFailurei386(bugnumber=None): return expectedFailureArch('i386', bugnumber) @@ -652,10 +555,10 @@ def expectedFailurex86_64(bugnumber=None): return expectedFailureArch('x86_64', bugnumber) def expectedFailureOS(oslist, bugnumber=None, compilers=None, debug_info=None, archs=None): - return decorateTest(DecorateMode.Xfail, oslist=oslist, bugnumber=bugnumber, compiler=compilers, archs=archs, debug_info=debug_info) + return decorators.expectedFailureAll(oslist=oslist, bugnumber=bugnumber, compiler=compilers, archs=archs, debug_info=debug_info) def expectedFailureHostOS(oslist, bugnumber=None, compilers=None): - return decorateTest(DecorateMode.Xfail, hostoslist=oslist, bugnumber=bugnumber) + return decorators.expectedFailureAll(hostoslist=oslist, bugnumber=bugnumber) def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None): # For legacy reasons, we support both "darwin" and "macosx" as OS X triples. @@ -686,7 +589,7 @@ def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None): arch - A sequence of architecture names specifying the architectures for which a test is expected to fail. None means all architectures. """ - return expectedFailure(skip_for_android("xfailing on android", api_levels, archs), bugnumber) + return decorators.expectedFailure(skip_for_android("xfailing on android", api_levels, archs), bugnumber) # Flakey tests get two chances to run. If they fail the first time round, the result formatter # makes sure it is run one more time. @@ -764,13 +667,13 @@ def skipIfRemote(func): """Decorate the item to skip tests if testing remotely.""" def is_remote(): return "skip on remote platform" if lldb.remote_platform else None - return skipTestIfFn(is_remote)(func) + return decorators.skipTestIfFn(is_remote)(func) def skipIfRemoteDueToDeadlock(func): """Decorate the item to skip tests if testing remotely due to the test deadlocking.""" def is_remote(): return "skip on remote platform (deadlocks)" if lldb.remote_platform else None - return skipTestIfFn(is_remote)(func) + return decorators.skipTestIfFn(is_remote)(func) def skipIfNoSBHeaders(func): """Decorate the item to mark tests that should be skipped when LLDB is built with no SB API headers.""" @@ -784,13 +687,13 @@ def skipIfNoSBHeaders(func): return "skip because LLDB.h header not found" return None - return skipTestIfFn(are_sb_headers_missing)(func) + return decorators.skipTestIfFn(are_sb_headers_missing)(func) def skipIfiOSSimulator(func): """Decorate the item to skip tests that should be skipped on the iOS Simulator.""" def is_ios_simulator(): return "skip on the iOS Simulator" if configuration.lldb_platform_name == 'ios-simulator' else None - return skipTestIfFn(is_ios_simulator)(func) + return decorators.skipTestIfFn(is_ios_simulator)(func) def skipIfFreeBSD(func): """Decorate the item to skip tests that should be skipped on FreeBSD.""" @@ -849,7 +752,7 @@ def skipUnlessGoInstalled(func): return "skipping because available version ({}) does not meet minimum required version ({})".format( compiler_strict_version, min_strict_version) return None - return skipTestIfFn(is_go_missing)(func) + return decorators.skipTestIfFn(is_go_missing)(func) def getPlatform(): """Returns the target platform which the tests are running on.""" @@ -860,22 +763,6 @@ def getPlatform(): platform = 'netbsd' return platform -def getHostPlatform(): - """Returns the host platform running the test suite.""" - # Attempts to return a platform name matching a target Triple platform. - if sys.platform.startswith('linux'): - return 'linux' - elif sys.platform.startswith('win32'): - return 'windows' - elif sys.platform.startswith('darwin'): - return 'darwin' - elif sys.platform.startswith('freebsd'): - return 'freebsd' - elif sys.platform.startswith('netbsd'): - return 'netbsd' - else: - return sys.platform - def platformIsDarwin(): """Returns true if the OS triple for the selected platform is any valid apple OS""" return getPlatform() in getDarwinOSTriples() @@ -884,7 +771,7 @@ def skipIfHostIncompatibleWithRemote(func): """Decorate the item to skip tests if binaries built on this host are incompatible.""" def is_host_incompatible_with_remote(self): host_arch = self.getLldbArchitecture() - host_platform = getHostPlatform() + host_platform = lldbplatformutil.getHostPlatform() target_arch = self.getArchitecture() target_platform = 'darwin' if self.platformIsDarwin() else self.getPlatform() if not (target_arch == 'x86_64' and host_arch == 'i386') and host_arch != target_arch: @@ -892,15 +779,15 @@ def skipIfHostIncompatibleWithRemote(func): elif target_platform != host_platform: return "skipping because target is %s but host is %s" % (target_platform, host_platform) return None - return skipTestIfFn(is_host_incompatible_with_remote)(func) + return decorators.skipTestIfFn(is_host_incompatible_with_remote)(func) def skipIfHostPlatform(oslist): """Decorate the item to skip tests if running on one of the listed host platforms.""" - return skipIf(hostoslist=oslist) + return decorators.skipIf(hostoslist=oslist) def skipUnlessHostPlatform(oslist): """Decorate the item to skip tests unless running on one of the listed host platforms.""" - return skipIf(hostoslist=not_in(oslist)) + return decorators.skipIf(hostoslist=not_in(oslist)) def skipUnlessArch(archs): """Decorate the item to skip tests unless running on one of the listed architectures.""" @@ -935,85 +822,9 @@ def skipUnlessPlatform(oslist): return unittest2.skipUnless(getPlatform() in oslist, "requires on of %s" % (", ".join(oslist))) -# provide a function to skip on defined oslist, compiler version, and archs -# if none is specified for any argument, that argument won't be checked and thus means for all -# for example, -# @skipIf, skip for all platform/compiler/arch, -# @skipIf(compiler='gcc'), skip for gcc on all platform/architecture -# @skipIf(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), skip for gcc>=4.9 on linux with i386 - -# TODO: refactor current code, to make skipIfxxx functions to call this function -def decorateTest(mode, - bugnumber=None, oslist=None, hostoslist=None, - compiler=None, compiler_version=None, - archs=None, triple=None, - debug_info=None, - swig_version=None, py_version=None, - remote=None): - def fn(self): - skip_for_os = check_list_or_lambda(oslist, self.getPlatform()) - skip_for_hostos = check_list_or_lambda(hostoslist, getHostPlatform()) - skip_for_compiler = check_list_or_lambda(self.getCompiler(), compiler) and self.expectedCompilerVersion(compiler_version) - skip_for_arch = check_list_or_lambda(archs, self.getArchitecture()) - skip_for_debug_info = check_list_or_lambda(debug_info, self.debug_info) - skip_for_triple = triple is None or re.match(triple, lldb.DBG.GetSelectedPlatform().GetTriple()) - skip_for_swig_version = (swig_version is None) or (not hasattr(lldb, 'swig_version')) or (check_expected_version(swig_version[0], swig_version[1], lldb.swig_version)) - skip_for_py_version = (py_version is None) or check_expected_version(py_version[0], py_version[1], sys.version_info) - skip_for_remote = (remote is None) or (remote == (lldb.remote_platform is not None)) - - # For the test to be skipped, all specified (e.g. not None) parameters must be True. - # An unspecified parameter means "any", so those are marked skip by default. And we skip - # the final test if all conditions are True. - conditions = [(oslist, skip_for_os, "target o/s"), - (hostoslist, skip_for_hostos, "host o/s"), - (compiler, skip_for_compiler, "compiler or version"), - (archs, skip_for_arch, "architecture"), - (debug_info, skip_for_debug_info, "debug info format"), - (triple, skip_for_triple, "target triple"), - (swig_version, skip_for_swig_version, "swig version"), - (py_version, skip_for_py_version, "python version"), - (remote, skip_for_remote, "platform locality (remote/local)")] - reasons = [] - final_skip_result = True - for this_condition in conditions: - final_skip_result = final_skip_result and this_condition[1] - if this_condition[0] is not None and this_condition[1]: - reasons.append(this_condition[2]) - reason_str = None - if final_skip_result: - mode_str = {DecorateMode.Skip : "skipping", DecorateMode.Xfail : "xfailing"}[mode] - if len(reasons) > 0: - reason_str = ",".join(reasons) - reason_str = "{} due to the following parameter(s): {}".format(mode_str, reason_str) - else: - reason_str = "{} unconditionally" - return reason_str - - if mode == DecorateMode.Skip: - return skipTestIfFn(fn, bugnumber) - elif mode == DecorateMode.Xfail: - return expectedFailure(fn, bugnumber) - else: - return None - -def skipIf(bugnumber=None, - oslist=None, hostoslist=None, - compiler=None, compiler_version=None, - archs=None, triple=None, - debug_info=None, - swig_version=None, py_version=None, - remote=None): - return decorateTest(DecorateMode.Skip, - bugnumber=bugnumber, - oslist=oslist, hostoslist=hostoslist, - compiler=compiler, compiler_version=compiler_version, - archs=archs, triple=triple, - debug_info=debug_info, - swig_version=swig_version, py_version=py_version, - remote=remote) def skipIfDebugInfo(bugnumber=None, debug_info=None): - return skipIf(bugnumber=bugnumber, debug_info=debug_info) + return decorators.skipIf(bugnumber=bugnumber, debug_info=debug_info) def skipIfDWO(bugnumber=None): return skipIfDebugInfo(bugnumber, ["dwo"]) @@ -1024,45 +835,17 @@ def skipIfDwarf(bugnumber=None): def skipIfDsym(bugnumber=None): return skipIfDebugInfo(bugnumber, ["dsym"]) -def skipTestIfFn(expected_fn, bugnumber=None): - def skipTestIfFn_impl(func): - if isinstance(func, type) and issubclass(func, unittest2.TestCase): - raise Exception("@skipTestIfFn can only be used to decorate a test method") - - @wraps(func) - def wrapper(*args, **kwargs): - from unittest2 import case - self = args[0] - if does_function_require_self(expected_fn): - reason = expected_fn(self) - else: - reason = expected_fn() - if reason is not None: - self.skipTest(reason) - else: - func(*args, **kwargs) - return wrapper - - # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows) - # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])). When called - # the first way, the first argument will be the actual function because decorators are - # weird like that. So this is basically a check that says "how was the decorator used" - if six.callable(bugnumber): - return skipTestIfFn_impl(bugnumber) - else: - return skipTestIfFn_impl - def skipIfGcc(func): """Decorate the item to skip tests that should be skipped if building with gcc .""" - return skipIf(compiler="gcc")(func) + return decorators.skipIf(compiler="gcc")(func) def skipIfIcc(func): """Decorate the item to skip tests that should be skipped if building with icc .""" - return skipIf(compiler="icc")(func) + return decorators.skipIf(compiler="icc")(func) def skipIfi386(func): """Decorate the item to skip tests that should be skipped if building 32-bit.""" - return skipIf(archs="i386")(func) + return decorators.skipIf(archs="i386")(func) def skipIfTargetAndroid(api_levels=None, archs=None): """Decorator to skip tests when the target is Android. @@ -1073,14 +856,14 @@ def skipIfTargetAndroid(api_levels=None, archs=None): arch - A sequence of architecture names specifying the architectures for which a test is skipped. None means all architectures. """ - return skipTestIfFn(skip_for_android("skipping for android", api_levels, archs)) + return decorators.skipTestIfFn(skip_for_android("skipping for android", api_levels, archs)) def skipUnlessCompilerRt(func): """Decorate the item to skip tests if testing remotely.""" def is_compiler_rt_missing(): compilerRtPath = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "llvm","projects","compiler-rt") return "compiler-rt not found" if not os.path.exists(compilerRtPath) else None - return skipTestIfFn(is_compiler_rt_missing)(func) + return decorators.skipTestIfFn(is_compiler_rt_missing)(func) class _PlatformContext(object): """Value object class which contains platform-specific options.""" @@ -1509,7 +1292,7 @@ class Base(unittest2.TestCase): for hook in reversed(self.hooks): with recording(self, traceAlways) as sbuf: print("Executing tearDown hook:", getsource_if_available(hook), file=sbuf) - if does_function_require_self(hook): + if funcutils.requires_self(hook): hook(self) else: hook() # try the plain call and hope it works |