A number of improvements to decorator conditionals.

* Change the `not_in` function to be called `no_match`.  This makes
  it clear that keyword arguments can be more than just lists.
* Change the name of `_check_list_or_lambda` to
  `_match_decorator_property`.  Again clarifying that decorator params
  are not always lists.
* Always use a regex match when matching strings.  This allows automatic
  support for regex matching on all decorator properties.  Also support
  compiled regex values.
* Fix a bug in the compiler check used by _decorateTest.  The two
  arguments were reversed, the condition was always wrong.
* Change one test that uses skipUnlessArch to use skipIf, to
  demonstrate that skipIf can now handle more scenarios.

Differential Revision: http://reviews.llvm.org/D16938

llvm-svn: 260135
This commit is contained in:
Zachary Turner 2016-02-08 19:35:18 +00:00
parent 4a289a93f7
commit 2e887acea8
4 changed files with 30 additions and 28 deletions

View File

@ -25,6 +25,13 @@ from lldbsuite.test import lldbplatformutil
class DecorateMode: class DecorateMode:
Skip, Xfail = range(2) Skip, Xfail = range(2)
# You can use no_match to reverse the test of the conditional that is used to match keyword
# arguments in the skip / xfail decorators. If oslist=["windows", "linux"] skips windows
# and linux, oslist=no_match(["windows", "linux"]) skips *unless* windows or linux.
class no_match:
def __init__(self, item):
self.item = item
def _check_expected_version(comparison, expected, actual): def _check_expected_version(comparison, expected, actual):
def fn_leq(x,y): return x <= y def fn_leq(x,y): return x <= y
@ -49,18 +56,18 @@ def _check_expected_version(comparison, expected, actual):
return op_lookup[comparison](LooseVersion(actual_str), LooseVersion(expected_str)) return op_lookup[comparison](LooseVersion(actual_str), LooseVersion(expected_str))
def _check_list_or_lambda(list_or_lambda, value): def _match_decorator_property(expected, actual):
if six.callable(list_or_lambda): if actual is None or expected is None:
return list_or_lambda(value) return True
elif isinstance(list_or_lambda, list):
for item in list_or_lambda: if isinstance(expected, no_match):
if value in item: return not _match_decorator_property(expected.item, actual)
return True elif isinstance(expected, (str, re._pattern_type)):
return False return re.search(expected, actual) is not None
elif isinstance(list_or_lambda, str): elif hasattr(expected, "__iter__"):
return value is None or value in list_or_lambda return any([x is not None and _match_decorator_property(x, actual) for x in expected])
else: else:
return list_or_lambda is None or value is None or list_or_lambda == value return expected == actual
def expectedFailure(expected_fn, bugnumber=None): def expectedFailure(expected_fn, bugnumber=None):
def expectedFailure_impl(func): def expectedFailure_impl(func):
@ -131,15 +138,16 @@ def _decorateTest(mode,
swig_version=None, py_version=None, swig_version=None, py_version=None,
remote=None): remote=None):
def fn(self): def fn(self):
skip_for_os = _check_list_or_lambda(oslist, self.getPlatform()) skip_for_os = _match_decorator_property(oslist, self.getPlatform())
skip_for_hostos = _check_list_or_lambda(hostoslist, lldbplatformutil.getHostPlatform()) skip_for_hostos = _match_decorator_property(hostoslist, lldbplatformutil.getHostPlatform())
skip_for_compiler = _check_list_or_lambda(self.getCompiler(), compiler) and self.expectedCompilerVersion(compiler_version) skip_for_compiler = _match_decorator_property(compiler, self.getCompiler()) and self.expectedCompilerVersion(compiler_version)
skip_for_arch = _check_list_or_lambda(archs, self.getArchitecture()) skip_for_arch = _match_decorator_property(archs, self.getArchitecture())
skip_for_debug_info = _check_list_or_lambda(debug_info, self.debug_info) skip_for_debug_info = _match_decorator_property(debug_info, self.debug_info)
skip_for_triple = triple is None or re.match(triple, lldb.DBG.GetSelectedPlatform().GetTriple()) skip_for_triple = _match_decorator_property(triple, lldb.DBG.GetSelectedPlatform().GetTriple())
skip_for_remote = _match_decorator_property(remote, lldb.remote_platform is not None)
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_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_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. # 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 # An unspecified parameter means "any", so those are marked skip by default. And we skip
@ -283,12 +291,6 @@ def not_remote_testsuite_ready(func):
return "Not ready for remote testsuite" if lldb.remote_platform else None return "Not ready for remote testsuite" if lldb.remote_platform else None
return skipTestIfFn(is_remote)(func) return 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.
def not_in(iterable):
return lambda x : x not in iterable
def _match_architectures(archs, actual_arch): def _match_architectures(archs, actual_arch):
retype = type(re.compile('hello, world')) retype = type(re.compile('hello, world'))
list_passes = isinstance(archs, list) and actual_arch in archs list_passes = isinstance(archs, list) and actual_arch in archs
@ -555,7 +557,7 @@ def skipIfHostPlatform(oslist):
def skipUnlessHostPlatform(oslist): def skipUnlessHostPlatform(oslist):
"""Decorate the item to skip tests unless running on one of the listed host platforms.""" """Decorate the item to skip tests unless running on one of the listed host platforms."""
return skipIf(hostoslist=not_in(oslist)) return skipIf(hostoslist=no_match(oslist))
def skipUnlessArch(archs): def skipUnlessArch(archs):
"""Decorate the item to skip tests unless running on one of the listed architectures.""" """Decorate the item to skip tests unless running on one of the listed architectures."""

View File

@ -16,7 +16,7 @@ class AvoidBreakpointInDelaySlotAPITestCase(TestBase):
mydir = TestBase.compute_mydir(__file__) mydir = TestBase.compute_mydir(__file__)
@skipUnlessArch(archs=re.compile('mips*')) @skipIf(archs=no_match(re.compile('mips*')))
def test(self): def test(self):
self.build() self.build()
exe = os.path.join(os.getcwd(), "a.out") exe = os.path.join(os.getcwd(), "a.out")

View File

@ -14,7 +14,7 @@ class DebugBreakTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__) mydir = TestBase.compute_mydir(__file__)
@skipIf(archs=not_in(["i386", "i686"])) @skipIf(archs=no_match(["i386", "i686"]))
@no_debug_info_test @no_debug_info_test
def test_asm_int_3(self): def test_asm_int_3(self):
"""Test that intrinsics like `__debugbreak();` and `asm {"int3"}` are treated like breakpoints.""" """Test that intrinsics like `__debugbreak();` and `asm {"int3"}` are treated like breakpoints."""

View File

@ -7,7 +7,7 @@ class TestWithLimitDebugInfo(TestBase):
mydir = TestBase.compute_mydir(__file__) mydir = TestBase.compute_mydir(__file__)
@skipIf(debug_info=not_in(["dwarf"])) @skipIf(debug_info=no_match(["dwarf"]))
def test_limit_debug_info(self): def test_limit_debug_info(self):
self.build() self.build()