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