1from __future__ import print_function 2from __future__ import absolute_import 3 4# System modules 5from distutils.version import LooseVersion, StrictVersion 6from functools import wraps 7import itertools 8import os 9import re 10import sys 11 12# Third-party modules 13import six 14import unittest2 15 16# LLDB modules 17import use_lldb_suite 18 19import lldb 20from . import configuration 21from . import test_categories 22from .result_formatter import EventBuilder 23from lldbsuite.support import funcutils 24from lldbsuite.test import lldbplatform 25from lldbsuite.test import lldbplatformutil 26 27class DecorateMode: 28 Skip, Xfail = range(2) 29 30 31# You can use no_match to reverse the test of the conditional that is used to match keyword 32# arguments in the skip / xfail decorators. If oslist=["windows", "linux"] skips windows 33# and linux, oslist=no_match(["windows", "linux"]) skips *unless* windows or linux. 34class no_match: 35 def __init__(self, item): 36 self.item = item 37 38def _check_expected_version(comparison, expected, actual): 39 def fn_leq(x,y): return x <= y 40 def fn_less(x,y): return x < y 41 def fn_geq(x,y): return x >= y 42 def fn_greater(x,y): return x > y 43 def fn_eq(x,y): return x == y 44 def fn_neq(x,y): return x != y 45 46 op_lookup = { 47 "==": fn_eq, 48 "=": fn_eq, 49 "!=": fn_neq, 50 "<>": fn_neq, 51 ">": fn_greater, 52 "<": fn_less, 53 ">=": fn_geq, 54 "<=": fn_leq 55 } 56 expected_str = '.'.join([str(x) for x in expected]) 57 actual_str = '.'.join([str(x) for x in actual]) 58 59 return op_lookup[comparison](LooseVersion(actual_str), LooseVersion(expected_str)) 60 61def _match_decorator_property(expected, actual): 62 if actual is None or expected is None: 63 return True 64 65 if isinstance(expected, no_match): 66 return not _match_decorator_property(expected.item, actual) 67 elif isinstance(expected, (re._pattern_type,)+six.string_types): 68 return re.search(expected, actual) is not None 69 elif hasattr(expected, "__iter__"): 70 return any([x is not None and _match_decorator_property(x, actual) for x in expected]) 71 else: 72 return expected == actual 73 74def expectedFailure(expected_fn, bugnumber=None): 75 def expectedFailure_impl(func): 76 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 77 raise Exception("Decorator can only be used to decorate a test method") 78 @wraps(func) 79 def wrapper(*args, **kwargs): 80 from unittest2 import case 81 self = args[0] 82 if funcutils.requires_self(expected_fn): 83 xfail_reason = expected_fn(self) 84 else: 85 xfail_reason = expected_fn() 86 if xfail_reason is not None: 87 if configuration.results_formatter_object is not None: 88 # Mark this test as expected to fail. 89 configuration.results_formatter_object.handle_event( 90 EventBuilder.event_for_mark_test_expected_failure(self)) 91 xfail_func = unittest2.expectedFailure(func) 92 xfail_func(*args, **kwargs) 93 else: 94 func(*args, **kwargs) 95 return wrapper 96 # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows) 97 # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])). When called 98 # the first way, the first argument will be the actual function because decorators are 99 # weird like that. So this is basically a check that says "which syntax was the original 100 # function decorated with?" 101 if six.callable(bugnumber): 102 return expectedFailure_impl(bugnumber) 103 else: 104 return expectedFailure_impl 105 106def skipTestIfFn(expected_fn, bugnumber=None): 107 def skipTestIfFn_impl(func): 108 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 109 raise Exception("@skipTestIfFn can only be used to decorate a test method") 110 111 @wraps(func) 112 def wrapper(*args, **kwargs): 113 from unittest2 import case 114 self = args[0] 115 if funcutils.requires_self(expected_fn): 116 reason = expected_fn(self) 117 else: 118 reason = expected_fn() 119 120 if reason is not None: 121 self.skipTest(reason) 122 else: 123 func(*args, **kwargs) 124 return wrapper 125 126 # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows) 127 # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])). When called 128 # the first way, the first argument will be the actual function because decorators are 129 # weird like that. So this is basically a check that says "how was the decorator used" 130 if six.callable(bugnumber): 131 return skipTestIfFn_impl(bugnumber) 132 else: 133 return skipTestIfFn_impl 134 135def _decorateTest(mode, 136 bugnumber=None, oslist=None, hostoslist=None, 137 compiler=None, compiler_version=None, 138 archs=None, triple=None, 139 debug_info=None, 140 swig_version=None, py_version=None, 141 remote=None): 142 def fn(self): 143 skip_for_os = _match_decorator_property(lldbplatform.translate(oslist), self.getPlatform()) 144 skip_for_hostos = _match_decorator_property(lldbplatform.translate(hostoslist), lldbplatformutil.getHostPlatform()) 145 skip_for_compiler = _match_decorator_property(compiler, self.getCompiler()) and self.expectedCompilerVersion(compiler_version) 146 skip_for_arch = _match_decorator_property(archs, self.getArchitecture()) 147 skip_for_debug_info = _match_decorator_property(debug_info, self.debug_info) 148 skip_for_triple = _match_decorator_property(triple, lldb.DBG.GetSelectedPlatform().GetTriple()) 149 skip_for_remote = _match_decorator_property(remote, lldb.remote_platform is not None) 150 151 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)) 152 skip_for_py_version = (py_version is None) or _check_expected_version(py_version[0], py_version[1], sys.version_info) 153 154 # For the test to be skipped, all specified (e.g. not None) parameters must be True. 155 # An unspecified parameter means "any", so those are marked skip by default. And we skip 156 # the final test if all conditions are True. 157 conditions = [(oslist, skip_for_os, "target o/s"), 158 (hostoslist, skip_for_hostos, "host o/s"), 159 (compiler, skip_for_compiler, "compiler or version"), 160 (archs, skip_for_arch, "architecture"), 161 (debug_info, skip_for_debug_info, "debug info format"), 162 (triple, skip_for_triple, "target triple"), 163 (swig_version, skip_for_swig_version, "swig version"), 164 (py_version, skip_for_py_version, "python version"), 165 (remote, skip_for_remote, "platform locality (remote/local)")] 166 reasons = [] 167 final_skip_result = True 168 for this_condition in conditions: 169 final_skip_result = final_skip_result and this_condition[1] 170 if this_condition[0] is not None and this_condition[1]: 171 reasons.append(this_condition[2]) 172 reason_str = None 173 if final_skip_result: 174 mode_str = {DecorateMode.Skip : "skipping", DecorateMode.Xfail : "xfailing"}[mode] 175 if len(reasons) > 0: 176 reason_str = ",".join(reasons) 177 reason_str = "{} due to the following parameter(s): {}".format(mode_str, reason_str) 178 else: 179 reason_str = "{} unconditionally" 180 if bugnumber is not None and not six.callable(bugnumber): 181 reason_str = reason_str + " [" + str(bugnumber) + "]" 182 return reason_str 183 184 if mode == DecorateMode.Skip: 185 return skipTestIfFn(fn, bugnumber) 186 elif mode == DecorateMode.Xfail: 187 return expectedFailure(fn, bugnumber) 188 else: 189 return None 190 191# provide a function to xfail on defined oslist, compiler version, and archs 192# if none is specified for any argument, that argument won't be checked and thus means for all 193# for example, 194# @expectedFailureAll, xfail for all platform/compiler/arch, 195# @expectedFailureAll(compiler='gcc'), xfail for gcc on all platform/architecture 196# @expectedFailureAll(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), xfail for gcc>=4.9 on linux with i386 197def expectedFailureAll(bugnumber=None, 198 oslist=None, hostoslist=None, 199 compiler=None, compiler_version=None, 200 archs=None, triple=None, 201 debug_info=None, 202 swig_version=None, py_version=None, 203 remote=None): 204 return _decorateTest(DecorateMode.Xfail, 205 bugnumber=bugnumber, 206 oslist=oslist, hostoslist=hostoslist, 207 compiler=compiler, compiler_version=compiler_version, 208 archs=archs, triple=triple, 209 debug_info=debug_info, 210 swig_version=swig_version, py_version=py_version, 211 remote=remote) 212 213 214# provide a function to skip on defined oslist, compiler version, and archs 215# if none is specified for any argument, that argument won't be checked and thus means for all 216# for example, 217# @skipIf, skip for all platform/compiler/arch, 218# @skipIf(compiler='gcc'), skip for gcc on all platform/architecture 219# @skipIf(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), skip for gcc>=4.9 on linux with i386 220def skipIf(bugnumber=None, 221 oslist=None, hostoslist=None, 222 compiler=None, compiler_version=None, 223 archs=None, triple=None, 224 debug_info=None, 225 swig_version=None, py_version=None, 226 remote=None): 227 return _decorateTest(DecorateMode.Skip, 228 bugnumber=bugnumber, 229 oslist=oslist, hostoslist=hostoslist, 230 compiler=compiler, compiler_version=compiler_version, 231 archs=archs, triple=triple, 232 debug_info=debug_info, 233 swig_version=swig_version, py_version=py_version, 234 remote=remote) 235 236def _skip_for_android(reason, api_levels, archs): 237 def impl(obj): 238 result = lldbplatformutil.match_android_device(obj.getArchitecture(), valid_archs=archs, valid_api_levels=api_levels) 239 return reason if result else None 240 return impl 241 242def add_test_categories(cat): 243 """Add test categories to a TestCase method""" 244 cat = test_categories.validate(cat, True) 245 def impl(func): 246 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 247 raise Exception("@add_test_categories can only be used to decorate a test method") 248 if hasattr(func, "categories"): 249 cat.extend(func.categories) 250 func.categories = cat 251 return func 252 253 return impl 254 255def benchmarks_test(func): 256 """Decorate the item as a benchmarks test.""" 257 def should_skip_benchmarks_test(): 258 return "benchmarks test" 259 260 # Mark this function as such to separate them from the regular tests. 261 result = skipTestIfFn(should_skip_benchmarks_test)(func) 262 result.__benchmarks_test__ = True 263 return result 264 265def no_debug_info_test(func): 266 """Decorate the item as a test what don't use any debug info. If this annotation is specified 267 then the test runner won't generate a separate test for each debug info format. """ 268 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 269 raise Exception("@no_debug_info_test can only be used to decorate a test method") 270 @wraps(func) 271 def wrapper(self, *args, **kwargs): 272 return func(self, *args, **kwargs) 273 274 # Mark this function as such to separate them from the regular tests. 275 wrapper.__no_debug_info_test__ = True 276 return wrapper 277 278def debugserver_test(func): 279 """Decorate the item as a debugserver test.""" 280 def should_skip_debugserver_test(): 281 return "debugserver tests" if configuration.dont_do_debugserver_test else None 282 return skipTestIfFn(should_skip_debugserver_test)(func) 283 284def llgs_test(func): 285 """Decorate the item as a lldb-server test.""" 286 def should_skip_llgs_tests(): 287 return "llgs tests" if configuration.dont_do_llgs_test else None 288 return skipTestIfFn(should_skip_llgs_tests)(func) 289 290def not_remote_testsuite_ready(func): 291 """Decorate the item as a test which is not ready yet for remote testsuite.""" 292 def is_remote(): 293 return "Not ready for remote testsuite" if lldb.remote_platform else None 294 return skipTestIfFn(is_remote)(func) 295 296def expectedFailureOS(oslist, bugnumber=None, compilers=None, debug_info=None, archs=None): 297 return expectedFailureAll(oslist=oslist, bugnumber=bugnumber, compiler=compilers, archs=archs, debug_info=debug_info) 298 299def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None): 300 # For legacy reasons, we support both "darwin" and "macosx" as OS X triples. 301 return expectedFailureOS(lldbplatform.darwin_all, bugnumber, compilers, debug_info=debug_info) 302 303def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None): 304 """ Mark a test as xfail for Android. 305 306 Arguments: 307 bugnumber - The LLVM pr associated with the problem. 308 api_levels - A sequence of numbers specifying the Android API levels 309 for which a test is expected to fail. None means all API level. 310 arch - A sequence of architecture names specifying the architectures 311 for which a test is expected to fail. None means all architectures. 312 """ 313 return expectedFailure(_skip_for_android("xfailing on android", api_levels, archs), bugnumber) 314 315# Flakey tests get two chances to run. If they fail the first time round, the result formatter 316# makes sure it is run one more time. 317def expectedFlakey(expected_fn, bugnumber=None): 318 def expectedFailure_impl(func): 319 @wraps(func) 320 def wrapper(*args, **kwargs): 321 self = args[0] 322 if expected_fn(self): 323 # Send event marking test as explicitly eligible for rerunning. 324 if configuration.results_formatter_object is not None: 325 # Mark this test as rerunnable. 326 configuration.results_formatter_object.handle_event( 327 EventBuilder.event_for_mark_test_rerun_eligible(self)) 328 func(*args, **kwargs) 329 return wrapper 330 # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows) 331 # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])). When called 332 # the first way, the first argument will be the actual function because decorators are 333 # weird like that. So this is basically a check that says "which syntax was the original 334 # function decorated with?" 335 if six.callable(bugnumber): 336 return expectedFailure_impl(bugnumber) 337 else: 338 return expectedFailure_impl 339 340def expectedFlakeyDwarf(bugnumber=None): 341 def fn(self): 342 return self.debug_info == "dwarf" 343 return expectedFlakey(fn, bugnumber) 344 345def expectedFlakeyDsym(bugnumber=None): 346 def fn(self): 347 return self.debug_info == "dwarf" 348 return expectedFlakey(fn, bugnumber) 349 350def expectedFlakeyOS(oslist, bugnumber=None, compilers=None): 351 def fn(self): 352 return (self.getPlatform() in oslist and 353 self.expectedCompiler(compilers)) 354 return expectedFlakey(fn, bugnumber) 355 356def expectedFlakeyDarwin(bugnumber=None, compilers=None): 357 # For legacy reasons, we support both "darwin" and "macosx" as OS X triples. 358 return expectedFlakeyOS(lldbplatformutil.getDarwinOSTriples(), bugnumber, compilers) 359 360def expectedFlakeyFreeBSD(bugnumber=None, compilers=None): 361 return expectedFlakeyOS(['freebsd'], bugnumber, compilers) 362 363def expectedFlakeyLinux(bugnumber=None, compilers=None): 364 return expectedFlakeyOS(['linux'], bugnumber, compilers) 365 366def expectedFlakeyNetBSD(bugnumber=None, compilers=None): 367 return expectedFlakeyOS(['netbsd'], bugnumber, compilers) 368 369def expectedFlakeyCompiler(compiler, compiler_version=None, bugnumber=None): 370 if compiler_version is None: 371 compiler_version=['=', None] 372 def fn(self): 373 return compiler in self.getCompiler() and self.expectedCompilerVersion(compiler_version) 374 return expectedFlakey(fn, bugnumber) 375 376# @expectedFlakeyClang('bugnumber', ['<=', '3.4']) 377def expectedFlakeyClang(bugnumber=None, compiler_version=None): 378 return expectedFlakeyCompiler('clang', compiler_version, bugnumber) 379 380# @expectedFlakeyGcc('bugnumber', ['<=', '3.4']) 381def expectedFlakeyGcc(bugnumber=None, compiler_version=None): 382 return expectedFlakeyCompiler('gcc', compiler_version, bugnumber) 383 384def expectedFlakeyAndroid(bugnumber=None, api_levels=None, archs=None): 385 return expectedFlakey(_skip_for_android("flakey on android", api_levels, archs), bugnumber) 386 387def skipIfRemote(func): 388 """Decorate the item to skip tests if testing remotely.""" 389 def is_remote(): 390 return "skip on remote platform" if lldb.remote_platform else None 391 return skipTestIfFn(is_remote)(func) 392 393def skipIfRemoteDueToDeadlock(func): 394 """Decorate the item to skip tests if testing remotely due to the test deadlocking.""" 395 def is_remote(): 396 return "skip on remote platform (deadlocks)" if lldb.remote_platform else None 397 return skipTestIfFn(is_remote)(func) 398 399def skipIfNoSBHeaders(func): 400 """Decorate the item to mark tests that should be skipped when LLDB is built with no SB API headers.""" 401 def are_sb_headers_missing(): 402 if lldbplatformutil.getHostPlatform() == 'darwin': 403 header = os.path.join(os.environ["LLDB_LIB_DIR"], 'LLDB.framework', 'Versions','Current','Headers','LLDB.h') 404 else: 405 header = os.path.join(os.environ["LLDB_SRC"], "include", "lldb", "API", "LLDB.h") 406 if not os.path.exists(header): 407 return "skip because LLDB.h header not found" 408 return None 409 410 return skipTestIfFn(are_sb_headers_missing)(func) 411 412def skipIfiOSSimulator(func): 413 """Decorate the item to skip tests that should be skipped on the iOS Simulator.""" 414 def is_ios_simulator(): 415 return "skip on the iOS Simulator" if configuration.lldb_platform_name == 'ios-simulator' else None 416 return skipTestIfFn(is_ios_simulator)(func) 417 418def skipIfFreeBSD(func): 419 """Decorate the item to skip tests that should be skipped on FreeBSD.""" 420 return skipIfPlatform(["freebsd"])(func) 421 422def skipIfNetBSD(func): 423 """Decorate the item to skip tests that should be skipped on NetBSD.""" 424 return skipIfPlatform(["netbsd"])(func) 425 426def skipIfDarwin(func): 427 """Decorate the item to skip tests that should be skipped on Darwin.""" 428 return skipIfPlatform(lldbplatform.translate(lldbplatform.darwin_all))(func) 429 430def skipIfLinux(func): 431 """Decorate the item to skip tests that should be skipped on Linux.""" 432 return skipIfPlatform(["linux"])(func) 433 434def skipIfWindows(func): 435 """Decorate the item to skip tests that should be skipped on Windows.""" 436 return skipIfPlatform(["windows"])(func) 437 438def skipUnlessWindows(func): 439 """Decorate the item to skip tests that should be skipped on any non-Windows platform.""" 440 return skipUnlessPlatform(["windows"])(func) 441 442def skipUnlessDarwin(func): 443 """Decorate the item to skip tests that should be skipped on any non Darwin platform.""" 444 return skipUnlessPlatform(lldbplatformutil.getDarwinOSTriples())(func) 445 446def skipUnlessGoInstalled(func): 447 """Decorate the item to skip tests when no Go compiler is available.""" 448 def is_go_missing(self): 449 compiler = self.getGoCompilerVersion() 450 if not compiler: 451 return "skipping because go compiler not found" 452 match_version = re.search(r"(\d+\.\d+(\.\d+)?)", compiler) 453 if not match_version: 454 # Couldn't determine version. 455 return "skipping because go version could not be parsed out of {}".format(compiler) 456 else: 457 min_strict_version = StrictVersion("1.4.0") 458 compiler_strict_version = StrictVersion(match_version.group(1)) 459 if compiler_strict_version < min_strict_version: 460 return "skipping because available version ({}) does not meet minimum required version ({})".format( 461 compiler_strict_version, min_strict_version) 462 return None 463 return skipTestIfFn(is_go_missing)(func) 464 465def skipIfHostIncompatibleWithRemote(func): 466 """Decorate the item to skip tests if binaries built on this host are incompatible.""" 467 def is_host_incompatible_with_remote(self): 468 host_arch = self.getLldbArchitecture() 469 host_platform = lldbplatformutil.getHostPlatform() 470 target_arch = self.getArchitecture() 471 target_platform = 'darwin' if self.platformIsDarwin() else self.getPlatform() 472 if not (target_arch == 'x86_64' and host_arch == 'i386') and host_arch != target_arch: 473 return "skipping because target %s is not compatible with host architecture %s" % (target_arch, host_arch) 474 elif target_platform != host_platform: 475 return "skipping because target is %s but host is %s" % (target_platform, host_platform) 476 return None 477 return skipTestIfFn(is_host_incompatible_with_remote)(func) 478 479def skipIfPlatform(oslist): 480 """Decorate the item to skip tests if running on one of the listed platforms.""" 481 # This decorator cannot be ported to `skipIf` yet because it is used on entire 482 # classes, which `skipIf` explicitly forbids. 483 return unittest2.skipIf(lldbplatformutil.getPlatform() in oslist, 484 "skip on %s" % (", ".join(oslist))) 485 486def skipUnlessPlatform(oslist): 487 """Decorate the item to skip tests unless running on one of the listed platforms.""" 488 # This decorator cannot be ported to `skipIf` yet because it is used on entire 489 # classes, which `skipIf` explicitly forbids. 490 return unittest2.skipUnless(lldbplatformutil.getPlatform() in oslist, 491 "requires on of %s" % (", ".join(oslist))) 492 493def skipIfTargetAndroid(api_levels=None, archs=None): 494 """Decorator to skip tests when the target is Android. 495 496 Arguments: 497 api_levels - The API levels for which the test should be skipped. If 498 it is None, then the test will be skipped for all API levels. 499 arch - A sequence of architecture names specifying the architectures 500 for which a test is skipped. None means all architectures. 501 """ 502 return skipTestIfFn(_skip_for_android("skipping for android", api_levels, archs)) 503 504def skipUnlessCompilerRt(func): 505 """Decorate the item to skip tests if testing remotely.""" 506 def is_compiler_rt_missing(): 507 compilerRtPath = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "llvm","projects","compiler-rt") 508 return "compiler-rt not found" if not os.path.exists(compilerRtPath) else None 509 return skipTestIfFn(is_compiler_rt_missing)(func) 510