zturner created this revision.
zturner added reviewers: labath, tberghammer, tfiala.
zturner added a subscriber: lldb-commits.
Herald added subscribers: srhines, danalbert, tberghammer.

This creates the `decorators.py` module and moves some of the low level common 
decorators there.

There are many more decorators not included here, but I didn't want to clutter 
up the patch with unnecessary spam of files that all I'm doing is just adding a 
new import statement.  So assuming people are ok with the high level direction 
/ approach used here, I'll submit this and then I'll do the follow up (that 
finishes off the rest of the decorators) without review.

http://reviews.llvm.org/D16872

Files:
  packages/Python/lldbsuite/support/funcutils.py
  packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py
  packages/Python/lldbsuite/test/decorators.py
  packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py
  packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py
  
packages/Python/lldbsuite/test/expression_command/persist_objc_pointeetype/TestPersistObjCPointeeType.py
  packages/Python/lldbsuite/test/functionalities/avoids-fd-leak/TestFdLeak.py
  
packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py
  
packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py
  
packages/Python/lldbsuite/test/functionalities/data-formatter/vector-types/TestVectorTypesFormatting.py
  
packages/Python/lldbsuite/test/functionalities/jitloader_gdb/TestJITLoaderGDB.py
  packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py
  packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py
  
packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
  
packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/TestCrashDuringStep.py
  
packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py
  packages/Python/lldbsuite/test/lang/c/const_variables/TestConstVariables.py
  packages/Python/lldbsuite/test/lang/c/global_variables/TestGlobalVariables.py
  
packages/Python/lldbsuite/test/lang/c/register_variables/TestRegisterVariables.py
  packages/Python/lldbsuite/test/lang/c/typedef/Testtypedef.py
  packages/Python/lldbsuite/test/lang/cpp/auto/TestCPPAuto.py
  
packages/Python/lldbsuite/test/lang/cpp/limit-debug-info/TestWithLimitDebugInfo.py
  packages/Python/lldbsuite/test/lang/cpp/virtual/TestVirtual.py
  packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py
  packages/Python/lldbsuite/test/linux/builtin_trap/TestBuiltinTrap.py
  packages/Python/lldbsuite/test/lldbplatformutil.py
  packages/Python/lldbsuite/test/lldbtest.py
  
packages/Python/lldbsuite/test/python_api/default-constructor/TestDefaultConstructorForAPIObjects.py
  
packages/Python/lldbsuite/test/python_api/disassemble-raw-data/TestDisassemble_VST1_64.py
  
packages/Python/lldbsuite/test/python_api/lldbutil/process/TestPrintStackTraces.py
  
packages/Python/lldbsuite/test/python_api/module_section/TestModuleAndSection.py
  
packages/Python/lldbsuite/test/python_api/value/linked_list/TestValueAPILinkedList.py
  
packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
  
packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py

Index: packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py
===================================================================
--- packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py
+++ packages/Python/lldbsuite/test/tools/lldb-server/platform-process-connect/TestPlatformProcessConnect.py
@@ -1,8 +1,9 @@
 from __future__ import print_function
 
 import gdbremote_testcase
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class TestPlatformProcessConnect(gdbremote_testcase.GdbRemoteTestCaseBase):
     mydir = TestBase.compute_mydir(__file__)
Index: packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
===================================================================
--- packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
+++ packages/Python/lldbsuite/test/python_api/watchpoint/watchlocation/TestTargetWatchAddress.py
@@ -9,8 +9,9 @@
 import os, time
 import re
 import lldb
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
 
 class TargetWatchAddressAPITestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/python_api/value/linked_list/TestValueAPILinkedList.py
===================================================================
--- packages/Python/lldbsuite/test/python_api/value/linked_list/TestValueAPILinkedList.py
+++ packages/Python/lldbsuite/test/python_api/value/linked_list/TestValueAPILinkedList.py
@@ -10,8 +10,9 @@
 import os, time
 import re
 import lldb
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
 
 class ValueAsLinkedListTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/python_api/module_section/TestModuleAndSection.py
===================================================================
--- packages/Python/lldbsuite/test/python_api/module_section/TestModuleAndSection.py
+++ packages/Python/lldbsuite/test/python_api/module_section/TestModuleAndSection.py
@@ -9,7 +9,9 @@
 import os, time
 import re
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
 from lldbsuite.test.lldbutil import symbol_type_to_str
 
 class ModuleAndSectionAPIsTestCase(TestBase):
Index: packages/Python/lldbsuite/test/python_api/lldbutil/process/TestPrintStackTraces.py
===================================================================
--- packages/Python/lldbsuite/test/python_api/lldbutil/process/TestPrintStackTraces.py
+++ packages/Python/lldbsuite/test/python_api/lldbutil/process/TestPrintStackTraces.py
@@ -9,7 +9,9 @@
 import os, time
 import re
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
 
 class ThreadsStackTracesTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/python_api/disassemble-raw-data/TestDisassemble_VST1_64.py
===================================================================
--- packages/Python/lldbsuite/test/python_api/disassemble-raw-data/TestDisassemble_VST1_64.py
+++ packages/Python/lldbsuite/test/python_api/disassemble-raw-data/TestDisassemble_VST1_64.py
@@ -9,8 +9,9 @@
 import os, time
 import re
 import lldb
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
 
 class Disassemble_VST1_64(TestBase):
 
Index: packages/Python/lldbsuite/test/python_api/default-constructor/TestDefaultConstructorForAPIObjects.py
===================================================================
--- packages/Python/lldbsuite/test/python_api/default-constructor/TestDefaultConstructorForAPIObjects.py
+++ packages/Python/lldbsuite/test/python_api/default-constructor/TestDefaultConstructorForAPIObjects.py
@@ -18,8 +18,9 @@
 import os, time
 import re
 import lldb
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
 
 class APIDefaultConstructorTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/lldbtest.py
===================================================================
--- packages/Python/lldbsuite/test/lldbtest.py
+++ packages/Python/lldbsuite/test/lldbtest.py
@@ -37,7 +37,6 @@
 # System modules
 import abc
 import collections
-from distutils.version import LooseVersion
 import gc
 import glob
 import inspect
@@ -60,11 +59,13 @@
 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 @@
         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 @@
         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 @@
     """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 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 @@
 
     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 @@
     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 @@
     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 @@
         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,25 @@
     """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 skipUnlessListedRemote(remote_list=None):
+    def is_remote_unlisted(self):
+        if remote_list and lldb.remote_platform:
+            triple = self.dbg.GetSelectedPlatform().GetTriple()
+            for r in remote_list:
+                if r in triple:
+                    return None
+            return "skipping because remote is not listed"
+        else:
+            return None
+    return decorators.skipTestIfFn(is_remote_unlisted)
 
 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 +699,13 @@
             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 +764,7 @@
                 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 +775,6 @@
         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 +783,7 @@
     """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 +791,15 @@
         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 +834,9 @@
     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 +847,17 @@
 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 +868,14 @@
         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 +1304,7 @@
         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
Index: packages/Python/lldbsuite/test/lldbplatformutil.py
===================================================================
--- packages/Python/lldbsuite/test/lldbplatformutil.py
+++ packages/Python/lldbsuite/test/lldbplatformutil.py
@@ -6,6 +6,7 @@
 # System modules
 import re
 import subprocess
+import sys
 
 # Third-party modules
 from six.moves.urllib import parse as urlparse
@@ -85,3 +86,19 @@
         if android_device_api() >= 16:
             dictionary["PIE"] = 1
     return dictionary
+
+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
Index: packages/Python/lldbsuite/test/linux/builtin_trap/TestBuiltinTrap.py
===================================================================
--- packages/Python/lldbsuite/test/linux/builtin_trap/TestBuiltinTrap.py
+++ packages/Python/lldbsuite/test/linux/builtin_trap/TestBuiltinTrap.py
@@ -9,8 +9,9 @@
 
 import os
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class BuiltinTrapTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py
===================================================================
--- packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py
+++ packages/Python/lldbsuite/test/lang/objc/objc-new-syntax/TestObjCNewSyntax.py
@@ -6,13 +6,14 @@
 
 import unittest2
 import os, time
-import lldb
 import platform
-import lldbsuite.test.lldbutil as lldbutil
 
 from distutils.version import StrictVersion
 
+import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
 
 class ObjCNewSyntaxTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/lang/cpp/virtual/TestVirtual.py
===================================================================
--- packages/Python/lldbsuite/test/lang/cpp/virtual/TestVirtual.py
+++ packages/Python/lldbsuite/test/lang/cpp/virtual/TestVirtual.py
@@ -7,8 +7,9 @@
 import os, time
 import re
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 def Msg(expr, val):
     return "'expression %s' matches the output (from compiled code): %s" % (expr, val)
Index: packages/Python/lldbsuite/test/lang/cpp/limit-debug-info/TestWithLimitDebugInfo.py
===================================================================
--- packages/Python/lldbsuite/test/lang/cpp/limit-debug-info/TestWithLimitDebugInfo.py
+++ packages/Python/lldbsuite/test/lang/cpp/limit-debug-info/TestWithLimitDebugInfo.py
@@ -1,6 +1,7 @@
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class TestWithLimitDebugInfo(TestBase):
 
Index: packages/Python/lldbsuite/test/lang/cpp/auto/TestCPPAuto.py
===================================================================
--- packages/Python/lldbsuite/test/lang/cpp/auto/TestCPPAuto.py
+++ packages/Python/lldbsuite/test/lang/cpp/auto/TestCPPAuto.py
@@ -2,8 +2,9 @@
 Tests that auto types work
 """
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class CPPAutoTestCase(TestBase):
     
Index: packages/Python/lldbsuite/test/lang/c/typedef/Testtypedef.py
===================================================================
--- packages/Python/lldbsuite/test/lang/c/typedef/Testtypedef.py
+++ packages/Python/lldbsuite/test/lang/c/typedef/Testtypedef.py
@@ -6,8 +6,9 @@
 
 import os, time
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class TypedefTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/lang/c/register_variables/TestRegisterVariables.py
===================================================================
--- packages/Python/lldbsuite/test/lang/c/register_variables/TestRegisterVariables.py
+++ packages/Python/lldbsuite/test/lang/c/register_variables/TestRegisterVariables.py
@@ -6,8 +6,9 @@
 
 import os, time
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class RegisterVariableTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/lang/c/global_variables/TestGlobalVariables.py
===================================================================
--- packages/Python/lldbsuite/test/lang/c/global_variables/TestGlobalVariables.py
+++ packages/Python/lldbsuite/test/lang/c/global_variables/TestGlobalVariables.py
@@ -3,8 +3,9 @@
 from __future__ import print_function
 
 
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class GlobalVariablesTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/lang/c/const_variables/TestConstVariables.py
===================================================================
--- packages/Python/lldbsuite/test/lang/c/const_variables/TestConstVariables.py
+++ packages/Python/lldbsuite/test/lang/c/const_variables/TestConstVariables.py
@@ -6,8 +6,9 @@
 
 import os, time
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class ConstVariableTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py
+++ packages/Python/lldbsuite/test/functionalities/watchpoint/hello_watchlocation/TestWatchLocation.py
@@ -9,8 +9,9 @@
 import os, time
 import re
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class HelloWatchLocationTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/TestCrashDuringStep.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/TestCrashDuringStep.py
+++ packages/Python/lldbsuite/test/functionalities/thread/crash_during_step/TestCrashDuringStep.py
@@ -8,8 +8,9 @@
 
 import os
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class CreateDuringStepTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
+++ packages/Python/lldbsuite/test/functionalities/thread/concurrent_events/TestConcurrentEvents.py
@@ -17,8 +17,9 @@
 import unittest2
 import os, time
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 @skipIfWindows
 class ConcurrentEventsTestCase(TestBase):
Index: packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py
+++ packages/Python/lldbsuite/test/functionalities/return-value/TestReturnValue.py
@@ -9,8 +9,9 @@
 import os, time
 import re
 import lldb
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
 
 class ReturnValueTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py
+++ packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py
@@ -9,8 +9,9 @@
 import os, time
 import re
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 @skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently
 class LoadUnloadTestCase(TestBase):
Index: packages/Python/lldbsuite/test/functionalities/jitloader_gdb/TestJITLoaderGDB.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/jitloader_gdb/TestJITLoaderGDB.py
+++ packages/Python/lldbsuite/test/functionalities/jitloader_gdb/TestJITLoaderGDB.py
@@ -2,13 +2,12 @@
 
 from __future__ import print_function
 
-
-
 import unittest2
 import os
 import lldb
+from lldbsuite.test import lldbutil
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
 import re
 
 
Index: packages/Python/lldbsuite/test/functionalities/data-formatter/vector-types/TestVectorTypesFormatting.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/data-formatter/vector-types/TestVectorTypesFormatting.py
+++ packages/Python/lldbsuite/test/functionalities/data-formatter/vector-types/TestVectorTypesFormatting.py
@@ -8,8 +8,9 @@
 
 import os, time
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class VectorTypesFormattingTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py
+++ packages/Python/lldbsuite/test/functionalities/breakpoint/debugbreak/TestDebugBreak.py
@@ -6,8 +6,9 @@
 
 import os
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class DebugBreakTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py
+++ packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_locations/TestBreakpointLocations.py
@@ -8,8 +8,9 @@
 
 import os, time
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class BreakpointLocationsTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/functionalities/avoids-fd-leak/TestFdLeak.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/avoids-fd-leak/TestFdLeak.py
+++ packages/Python/lldbsuite/test/functionalities/avoids-fd-leak/TestFdLeak.py
@@ -8,8 +8,9 @@
 
 import os
 import lldb
+from lldbsuite.test import lldbutil
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.decorators import *
 
 
 def python_leaky_fd_version(test):
Index: packages/Python/lldbsuite/test/expression_command/persist_objc_pointeetype/TestPersistObjCPointeeType.py
===================================================================
--- packages/Python/lldbsuite/test/expression_command/persist_objc_pointeetype/TestPersistObjCPointeeType.py
+++ packages/Python/lldbsuite/test/expression_command/persist_objc_pointeetype/TestPersistObjCPointeeType.py
@@ -7,8 +7,9 @@
 
 
 import lldb
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
 
 class PersistObjCPointeeType(TestBase):
 
Index: packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py
===================================================================
--- packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py
+++ packages/Python/lldbsuite/test/expression_command/macros/TestMacros.py
@@ -1,6 +1,10 @@
+from __future__ import print_function
+
+
 import lldb
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 
 class TestMacros(TestBase):
 
Index: packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py
===================================================================
--- packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py
+++ packages/Python/lldbsuite/test/expression_command/char/TestExprsChar.py
@@ -3,8 +3,9 @@
 
 
 import lldb
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
 
 class ExprCharTestCase(TestBase):
 
Index: packages/Python/lldbsuite/test/decorators.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/decorators.py
@@ -0,0 +1,220 @@
+from __future__ import print_function
+from __future__ import absolute_import
+
+# System modules
+from distutils.version import LooseVersion
+from functools import wraps
+import re
+import sys
+
+# Third-party modules
+import six
+import unittest2
+
+# LLDB modules
+import use_lldb_suite
+
+import lldb
+from . import configuration
+from .result_formatter import EventBuilder
+from lldbsuite.support import funcutils
+from lldbsuite.test import lldbplatformutil
+
+class DecorateMode:
+    Skip, Xfail = range(2)
+
+
+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))
+
+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 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]
+            if funcutils.requires_self(expected_fn):
+                xfail_reason = expected_fn(self)
+            else:
+                xfail_reason = expected_fn()
+            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
+
+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 funcutils.requires_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 _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, lldbplatformutil.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
+
+# 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)
+
+
+# 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
+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)
Index: packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py
===================================================================
--- packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py
+++ packages/Python/lldbsuite/test/api/multithreaded/TestMultithreaded.py
@@ -6,8 +6,9 @@
 
 
 import os, re
+from lldbsuite.test.decorators import *
 from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test import lldbutil
 import subprocess
 
 class SBBreakpointCallbackCase(TestBase):
Index: packages/Python/lldbsuite/support/funcutils.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/support/funcutils.py
@@ -0,0 +1,16 @@
+from __future__ import print_function
+from __future__ import absolute_import
+
+# System modules
+import inspect
+
+# Third-party modules
+
+# LLDB modules
+
+def requires_self(func):
+    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
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to