[lldb][NFC] Refactor _get_bool_config_skip_if_decorator
[lldb.git] / lldb / packages / Python / lldbsuite / test / decorators.py
1 from __future__ import absolute_import
2
3 # System modules
4 from distutils.version import LooseVersion
5 from functools import wraps
6 import ctypes
7 import locale
8 import os
9 import platform
10 import re
11 import sys
12 import tempfile
13 import subprocess
14
15 # Third-party modules
16 import six
17 import unittest2
18
19 # LLDB modules
20 import lldb
21 from . import configuration
22 from . import test_categories
23 from . import lldbtest_config
24 from lldbsuite.support import funcutils
25 from lldbsuite.test import lldbplatform
26 from lldbsuite.test import lldbplatformutil
27
28
29 class DecorateMode:
30     Skip, Xfail = range(2)
31
32
33 # You can use no_match to reverse the test of the conditional that is used to match keyword
34 # arguments in the skip / xfail decorators.  If oslist=["windows", "linux"] skips windows
35 # and linux, oslist=no_match(["windows", "linux"]) skips *unless* windows
36 # or linux.
37 class no_match:
38
39     def __init__(self, item):
40         self.item = item
41
42
43 def _check_expected_version(comparison, expected, actual):
44     def fn_leq(x, y): return x <= y
45
46     def fn_less(x, y): return x < y
47
48     def fn_geq(x, y): return x >= y
49
50     def fn_greater(x, y): return x > y
51
52     def fn_eq(x, y): return x == y
53
54     def fn_neq(x, y): return x != y
55
56     op_lookup = {
57         "==": fn_eq,
58         "=": fn_eq,
59         "!=": fn_neq,
60         "<>": fn_neq,
61         ">": fn_greater,
62         "<": fn_less,
63         ">=": fn_geq,
64         "<=": fn_leq
65     }
66     expected_str = '.'.join([str(x) for x in expected])
67     actual_str = '.'.join([str(x) for x in actual])
68
69     return op_lookup[comparison](
70         LooseVersion(actual_str),
71         LooseVersion(expected_str))
72
73
74 _re_pattern_type = type(re.compile(''))
75 def _match_decorator_property(expected, actual):
76     if actual is None or expected is None:
77         return True
78
79     if isinstance(expected, no_match):
80         return not _match_decorator_property(expected.item, actual)
81     elif isinstance(expected, (_re_pattern_type,) + six.string_types):
82         return re.search(expected, actual) is not None
83     elif hasattr(expected, "__iter__"):
84         return any([x is not None and _match_decorator_property(x, actual)
85                     for x in expected])
86     else:
87         return expected == actual
88
89 def expectedFailure(func):
90     return unittest2.expectedFailure(func)
91
92 def expectedFailureIfFn(expected_fn, bugnumber=None):
93     def expectedFailure_impl(func):
94         if isinstance(func, type) and issubclass(func, unittest2.TestCase):
95             raise Exception(
96                 "Decorator can only be used to decorate a test method")
97
98         @wraps(func)
99         def wrapper(*args, **kwargs):
100             xfail_reason = expected_fn(*args, **kwargs)
101             if xfail_reason is not None:
102                 xfail_func = unittest2.expectedFailure(func)
103                 xfail_func(*args, **kwargs)
104             else:
105                 func(*args, **kwargs)
106         return wrapper
107     # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows)
108     # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])).  When called
109     # the first way, the first argument will be the actual function because decorators are
110     # weird like that.  So this is basically a check that says "which syntax was the original
111     # function decorated with?"
112     if six.callable(bugnumber):
113         return expectedFailure_impl(bugnumber)
114     else:
115         return expectedFailure_impl
116
117
118 def skipTestIfFn(expected_fn, bugnumber=None):
119     def skipTestIfFn_impl(func):
120         if isinstance(func, type) and issubclass(func, unittest2.TestCase):
121             raise Exception(
122                 "@skipTestIfFn can only be used to decorate a test method")
123
124         @wraps(func)
125         def wrapper(*args, **kwargs):
126             self = args[0]
127             if funcutils.requires_self(expected_fn):
128                 reason = expected_fn(self)
129             else:
130                 reason = expected_fn()
131
132             if reason is not None:
133                 self.skipTest(reason)
134             else:
135                 return func(*args, **kwargs)
136         return wrapper
137
138     # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows)
139     # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])).  When called
140     # the first way, the first argument will be the actual function because decorators are
141     # weird like that.  So this is basically a check that says "how was the
142     # decorator used"
143     if six.callable(bugnumber):
144         return skipTestIfFn_impl(bugnumber)
145     else:
146         return skipTestIfFn_impl
147
148
149 def _decorateTest(mode,
150                   bugnumber=None, oslist=None, hostoslist=None,
151                   compiler=None, compiler_version=None,
152                   archs=None, triple=None,
153                   debug_info=None,
154                   swig_version=None, py_version=None,
155                   macos_version=None,
156                   remote=None, dwarf_version=None,
157                   setting=None):
158     def fn(self):
159         skip_for_os = _match_decorator_property(
160             lldbplatform.translate(oslist), self.getPlatform())
161         skip_for_hostos = _match_decorator_property(
162             lldbplatform.translate(hostoslist),
163             lldbplatformutil.getHostPlatform())
164         skip_for_compiler = _match_decorator_property(
165             compiler, self.getCompiler()) and self.expectedCompilerVersion(compiler_version)
166         skip_for_arch = _match_decorator_property(
167             archs, self.getArchitecture())
168         skip_for_debug_info = _match_decorator_property(
169             debug_info, self.getDebugInfo())
170         skip_for_triple = _match_decorator_property(
171             triple, lldb.selected_platform.GetTriple())
172         skip_for_remote = _match_decorator_property(
173             remote, lldb.remote_platform is not None)
174
175         skip_for_swig_version = (
176             swig_version is None) or (
177             not hasattr(
178                 lldb,
179                 'swig_version')) or (
180                 _check_expected_version(
181                     swig_version[0],
182                     swig_version[1],
183                     lldb.swig_version))
184         skip_for_py_version = (
185             py_version is None) or _check_expected_version(
186             py_version[0], py_version[1], sys.version_info)
187         skip_for_macos_version = (macos_version is None) or (
188             (platform.mac_ver()[0] != "") and (_check_expected_version(
189                 macos_version[0],
190                 macos_version[1],
191                 platform.mac_ver()[0])))
192         skip_for_dwarf_version = (dwarf_version is None) or (
193             _check_expected_version(dwarf_version[0], dwarf_version[1],
194                                     self.getDwarfVersion()))
195         skip_for_setting = (setting is None) or (
196             setting in configuration.settings)
197
198         # For the test to be skipped, all specified (e.g. not None) parameters must be True.
199         # An unspecified parameter means "any", so those are marked skip by default.  And we skip
200         # the final test if all conditions are True.
201         conditions = [(oslist, skip_for_os, "target o/s"),
202                       (hostoslist, skip_for_hostos, "host o/s"),
203                       (compiler, skip_for_compiler, "compiler or version"),
204                       (archs, skip_for_arch, "architecture"),
205                       (debug_info, skip_for_debug_info, "debug info format"),
206                       (triple, skip_for_triple, "target triple"),
207                       (swig_version, skip_for_swig_version, "swig version"),
208                       (py_version, skip_for_py_version, "python version"),
209                       (macos_version, skip_for_macos_version, "macOS version"),
210                       (remote, skip_for_remote, "platform locality (remote/local)"),
211                       (dwarf_version, skip_for_dwarf_version, "dwarf version"),
212                       (setting, skip_for_setting, "setting")]
213         reasons = []
214         final_skip_result = True
215         for this_condition in conditions:
216             final_skip_result = final_skip_result and this_condition[1]
217             if this_condition[0] is not None and this_condition[1]:
218                 reasons.append(this_condition[2])
219         reason_str = None
220         if final_skip_result:
221             mode_str = {
222                 DecorateMode.Skip: "skipping",
223                 DecorateMode.Xfail: "xfailing"}[mode]
224             if len(reasons) > 0:
225                 reason_str = ",".join(reasons)
226                 reason_str = "{} due to the following parameter(s): {}".format(
227                     mode_str, reason_str)
228             else:
229                 reason_str = "{} unconditionally"
230             if bugnumber is not None and not six.callable(bugnumber):
231                 reason_str = reason_str + " [" + str(bugnumber) + "]"
232         return reason_str
233
234     if mode == DecorateMode.Skip:
235         return skipTestIfFn(fn, bugnumber)
236     elif mode == DecorateMode.Xfail:
237         return expectedFailureIfFn(fn, bugnumber)
238     else:
239         return None
240
241 # provide a function to xfail on defined oslist, compiler version, and archs
242 # if none is specified for any argument, that argument won't be checked and thus means for all
243 # for example,
244 # @expectedFailureAll, xfail for all platform/compiler/arch,
245 # @expectedFailureAll(compiler='gcc'), xfail for gcc on all platform/architecture
246 # @expectedFailureAll(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), xfail for gcc>=4.9 on linux with i386
247
248
249 def expectedFailureAll(bugnumber=None,
250                        oslist=None, hostoslist=None,
251                        compiler=None, compiler_version=None,
252                        archs=None, triple=None,
253                        debug_info=None,
254                        swig_version=None, py_version=None,
255                        macos_version=None,
256                        remote=None, dwarf_version=None,
257                        setting=None):
258     return _decorateTest(DecorateMode.Xfail,
259                          bugnumber=bugnumber,
260                          oslist=oslist, hostoslist=hostoslist,
261                          compiler=compiler, compiler_version=compiler_version,
262                          archs=archs, triple=triple,
263                          debug_info=debug_info,
264                          swig_version=swig_version, py_version=py_version,
265                          macos_version=None,
266                          remote=remote,dwarf_version=dwarf_version,
267                          setting=setting)
268
269
270 # provide a function to skip on defined oslist, compiler version, and archs
271 # if none is specified for any argument, that argument won't be checked and thus means for all
272 # for example,
273 # @skipIf, skip for all platform/compiler/arch,
274 # @skipIf(compiler='gcc'), skip for gcc on all platform/architecture
275 # @skipIf(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), skip for gcc>=4.9 on linux with i386
276 def skipIf(bugnumber=None,
277            oslist=None, hostoslist=None,
278            compiler=None, compiler_version=None,
279            archs=None, triple=None,
280            debug_info=None,
281            swig_version=None, py_version=None,
282            macos_version=None,
283            remote=None, dwarf_version=None,
284            setting=None):
285     return _decorateTest(DecorateMode.Skip,
286                          bugnumber=bugnumber,
287                          oslist=oslist, hostoslist=hostoslist,
288                          compiler=compiler, compiler_version=compiler_version,
289                          archs=archs, triple=triple,
290                          debug_info=debug_info,
291                          swig_version=swig_version, py_version=py_version,
292                          macos_version=macos_version,
293                          remote=remote, dwarf_version=dwarf_version,
294                          setting=setting)
295
296
297 def _skip_for_android(reason, api_levels, archs):
298     def impl(obj):
299         result = lldbplatformutil.match_android_device(
300             obj.getArchitecture(), valid_archs=archs, valid_api_levels=api_levels)
301         return reason if result else None
302     return impl
303
304
305 def add_test_categories(cat):
306     """Add test categories to a TestCase method"""
307     cat = test_categories.validate(cat, True)
308
309     def impl(func):
310         if isinstance(func, type) and issubclass(func, unittest2.TestCase):
311             raise Exception(
312                 "@add_test_categories can only be used to decorate a test method")
313         try:
314             if hasattr(func, "categories"):
315                 cat.extend(func.categories)
316             setattr(func, "categories", cat)
317         except AttributeError:
318             raise Exception('Cannot assign categories to inline tests.')
319
320         return func
321
322     return impl
323
324
325 def benchmarks_test(func):
326     """Decorate the item as a benchmarks test."""
327     def should_skip_benchmarks_test():
328         return "benchmarks test"
329
330     # Mark this function as such to separate them from the regular tests.
331     result = skipTestIfFn(should_skip_benchmarks_test)(func)
332     result.__benchmarks_test__ = True
333     return result
334
335
336 def no_debug_info_test(func):
337     """Decorate the item as a test what don't use any debug info. If this annotation is specified
338        then the test runner won't generate a separate test for each debug info format. """
339     if isinstance(func, type) and issubclass(func, unittest2.TestCase):
340         raise Exception(
341             "@no_debug_info_test can only be used to decorate a test method")
342
343     @wraps(func)
344     def wrapper(self, *args, **kwargs):
345         return func(self, *args, **kwargs)
346
347     # Mark this function as such to separate them from the regular tests.
348     wrapper.__no_debug_info_test__ = True
349     return wrapper
350
351 def apple_simulator_test(platform):
352     """
353     Decorate the test as a test requiring a simulator for a specific platform.
354
355     Consider that a simulator is available if you have the corresponding SDK installed.
356     The SDK identifiers for simulators are iphonesimulator, appletvsimulator, watchsimulator
357     """
358     def should_skip_simulator_test():
359         if lldbplatformutil.getHostPlatform() != 'darwin':
360             return "simulator tests are run only on darwin hosts"
361         try:
362             DEVNULL = open(os.devnull, 'w')
363             output = subprocess.check_output(["xcodebuild", "-showsdks"], stderr=DEVNULL).decode("utf-8")
364             if re.search('%ssimulator' % platform, output):
365                 return None
366             else:
367                 return "%s simulator is not supported on this system." % platform
368         except subprocess.CalledProcessError:
369             return "Simulators are unsupported on this system (xcodebuild failed)"
370
371     return skipTestIfFn(should_skip_simulator_test)
372
373
374 def debugserver_test(func):
375     """Decorate the item as a debugserver test."""
376     def should_skip_debugserver_test():
377         return ("debugserver tests"
378                 if not configuration.debugserver_platform
379                 else None)
380     return skipTestIfFn(should_skip_debugserver_test)(func)
381
382
383 def llgs_test(func):
384     """Decorate the item as a lldb-server test."""
385     def should_skip_llgs_tests():
386         return ("llgs tests"
387                 if not configuration.llgs_platform
388                 else None)
389     return skipTestIfFn(should_skip_llgs_tests)(func)
390
391
392 def expectedFailureOS(
393         oslist,
394         bugnumber=None,
395         compilers=None,
396         debug_info=None,
397         archs=None):
398     return expectedFailureAll(
399         oslist=oslist,
400         bugnumber=bugnumber,
401         compiler=compilers,
402         archs=archs,
403         debug_info=debug_info)
404
405
406 def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None, archs=None):
407     # For legacy reasons, we support both "darwin" and "macosx" as OS X
408     # triples.
409     return expectedFailureOS(
410         lldbplatform.darwin_all,
411         bugnumber,
412         compilers,
413         debug_info=debug_info,
414         archs=archs)
415
416
417 def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None):
418     """ Mark a test as xfail for Android.
419
420     Arguments:
421         bugnumber - The LLVM pr associated with the problem.
422         api_levels - A sequence of numbers specifying the Android API levels
423             for which a test is expected to fail. None means all API level.
424         arch - A sequence of architecture names specifying the architectures
425             for which a test is expected to fail. None means all architectures.
426     """
427     return expectedFailureIfFn(
428         _skip_for_android(
429             "xfailing on android",
430             api_levels,
431             archs),
432         bugnumber)
433
434
435 def expectedFailureNetBSD(bugnumber=None):
436     return expectedFailureOS(
437         ['netbsd'],
438         bugnumber)
439
440 # TODO: This decorator does not do anything. Remove it.
441 def expectedFlakey(expected_fn, bugnumber=None):
442     def expectedFailure_impl(func):
443         @wraps(func)
444         def wrapper(*args, **kwargs):
445             func(*args, **kwargs)
446         return wrapper
447     # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows)
448     # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])).  When called
449     # the first way, the first argument will be the actual function because decorators are
450     # weird like that.  So this is basically a check that says "which syntax was the original
451     # function decorated with?"
452     if six.callable(bugnumber):
453         return expectedFailure_impl(bugnumber)
454     else:
455         return expectedFailure_impl
456
457
458 def expectedFlakeyOS(oslist, bugnumber=None, compilers=None):
459     def fn(self):
460         return (self.getPlatform() in oslist and
461                 self.expectedCompiler(compilers))
462     return expectedFlakey(fn, bugnumber)
463
464
465 def expectedFlakeyDarwin(bugnumber=None, compilers=None):
466     # For legacy reasons, we support both "darwin" and "macosx" as OS X
467     # triples.
468     return expectedFlakeyOS(
469         lldbplatformutil.getDarwinOSTriples(),
470         bugnumber,
471         compilers)
472
473
474 def expectedFlakeyFreeBSD(bugnumber=None, compilers=None):
475     return expectedFlakeyOS(['freebsd'], bugnumber, compilers)
476
477
478 def expectedFlakeyLinux(bugnumber=None, compilers=None):
479     return expectedFlakeyOS(['linux'], bugnumber, compilers)
480
481
482 def expectedFlakeyNetBSD(bugnumber=None, compilers=None):
483     return expectedFlakeyOS(['netbsd'], bugnumber, compilers)
484
485
486 def expectedFlakeyAndroid(bugnumber=None, api_levels=None, archs=None):
487     return expectedFlakey(
488         _skip_for_android(
489             "flakey on android",
490             api_levels,
491             archs),
492         bugnumber)
493
494 def skipIfOutOfTreeDebugserver(func):
495     """Decorate the item to skip tests if using an out-of-tree debugserver."""
496     def is_out_of_tree_debugserver():
497         return "out-of-tree debugserver" if lldbtest_config.out_of_tree_debugserver else None
498     return skipTestIfFn(is_out_of_tree_debugserver)(func)
499
500 def skipIfRemote(func):
501     """Decorate the item to skip tests if testing remotely."""
502     return unittest2.skipIf(lldb.remote_platform, "skip on remote platform")(func)
503
504
505 def skipIfNoSBHeaders(func):
506     """Decorate the item to mark tests that should be skipped when LLDB is built with no SB API headers."""
507     def are_sb_headers_missing():
508         if lldb.remote_platform:
509             return "skip because SBHeaders tests make no sense remotely"
510
511         if lldbplatformutil.getHostPlatform() == 'darwin' and configuration.lldb_framework_path:
512             header = os.path.join(
513                 configuration.lldb_framework_path,
514                 'Versions',
515                 'Current',
516                 'Headers',
517                 'LLDB.h')
518             if os.path.exists(header):
519                 return None
520
521         header = os.path.join(
522             os.environ["LLDB_SRC"],
523             "include",
524             "lldb",
525             "API",
526             "LLDB.h")
527         if not os.path.exists(header):
528             return "skip because LLDB.h header not found"
529         return None
530
531     return skipTestIfFn(are_sb_headers_missing)(func)
532
533
534 def skipIfRosetta(bugnumber):
535     """Skip a test when running the testsuite on macOS under the Rosetta translation layer."""
536     def is_running_rosetta(self):
537         if lldbplatformutil.getPlatform() in ['darwin', 'macosx']:
538             if (platform.uname()[5] == "arm") and (self.getArchitecture() == "x86_64"):
539                 return "skipped under Rosetta"
540         return None
541     return skipTestIfFn(is_running_rosetta)
542
543 def skipIfiOSSimulator(func):
544     """Decorate the item to skip tests that should be skipped on the iOS Simulator."""
545     def is_ios_simulator():
546         return "skip on the iOS Simulator" if configuration.lldb_platform_name == 'ios-simulator' else None
547     return skipTestIfFn(is_ios_simulator)(func)
548
549 def skipIfiOS(func):
550     return skipIfPlatform(lldbplatform.translate(lldbplatform.ios))(func)
551
552 def skipIftvOS(func):
553     return skipIfPlatform(lldbplatform.translate(lldbplatform.tvos))(func)
554
555 def skipIfwatchOS(func):
556     return skipIfPlatform(lldbplatform.translate(lldbplatform.watchos))(func)
557
558 def skipIfbridgeOS(func):
559     return skipIfPlatform(lldbplatform.translate(lldbplatform.bridgeos))(func)
560
561 def skipIfDarwinEmbedded(func):
562     """Decorate the item to skip tests that should be skipped on Darwin armv7/arm64 targets."""
563     return skipIfPlatform(
564         lldbplatform.translate(
565             lldbplatform.darwin_embedded))(func)
566
567 def skipIfDarwinSimulator(func):
568     """Decorate the item to skip tests that should be skipped on Darwin simulator targets."""
569     return skipIfPlatform(
570         lldbplatform.translate(
571             lldbplatform.darwin_simulator))(func)
572
573 def skipIfFreeBSD(func):
574     """Decorate the item to skip tests that should be skipped on FreeBSD."""
575     return skipIfPlatform(["freebsd"])(func)
576
577
578 def skipIfNetBSD(func):
579     """Decorate the item to skip tests that should be skipped on NetBSD."""
580     return skipIfPlatform(["netbsd"])(func)
581
582
583 def skipIfDarwin(func):
584     """Decorate the item to skip tests that should be skipped on Darwin."""
585     return skipIfPlatform(
586         lldbplatform.translate(
587             lldbplatform.darwin_all))(func)
588
589
590 def skipIfLinux(func):
591     """Decorate the item to skip tests that should be skipped on Linux."""
592     return skipIfPlatform(["linux"])(func)
593
594
595 def skipIfWindows(func):
596     """Decorate the item to skip tests that should be skipped on Windows."""
597     return skipIfPlatform(["windows"])(func)
598
599 def skipIfWindowsAndNonEnglish(func):
600     """Decorate the item to skip tests that should be skipped on non-English locales on Windows."""
601     def is_Windows_NonEnglish(self):
602         if sys.platform != "win32":
603             return None
604         kernel = ctypes.windll.kernel32
605         if locale.windows_locale[ kernel.GetUserDefaultUILanguage() ] == "en_US":
606             return None
607         return "skipping non-English Windows locale"
608     return skipTestIfFn(is_Windows_NonEnglish)(func)
609
610 def skipUnlessWindows(func):
611     """Decorate the item to skip tests that should be skipped on any non-Windows platform."""
612     return skipUnlessPlatform(["windows"])(func)
613
614
615 def skipUnlessDarwin(func):
616     """Decorate the item to skip tests that should be skipped on any non Darwin platform."""
617     return skipUnlessPlatform(lldbplatformutil.getDarwinOSTriples())(func)
618
619 def skipUnlessTargetAndroid(func):
620     return unittest2.skipUnless(lldbplatformutil.target_is_android(),
621                                 "requires target to be Android")(func)
622
623
624 def skipIfHostIncompatibleWithRemote(func):
625     """Decorate the item to skip tests if binaries built on this host are incompatible."""
626
627     def is_host_incompatible_with_remote(self):
628         host_arch = self.getLldbArchitecture()
629         host_platform = lldbplatformutil.getHostPlatform()
630         target_arch = self.getArchitecture()
631         target_platform = 'darwin' if self.platformIsDarwin() else self.getPlatform()
632         if not (target_arch == 'x86_64' and host_arch ==
633                 'i386') and host_arch != target_arch:
634             return "skipping because target %s is not compatible with host architecture %s" % (
635                 target_arch, host_arch)
636         if target_platform != host_platform:
637             return "skipping because target is %s but host is %s" % (
638                 target_platform, host_platform)
639         if lldbplatformutil.match_android_device(target_arch):
640             return "skipping because target is android"
641         return None
642     return skipTestIfFn(is_host_incompatible_with_remote)(func)
643
644
645 def skipIfPlatform(oslist):
646     """Decorate the item to skip tests if running on one of the listed platforms."""
647     # This decorator cannot be ported to `skipIf` yet because it is used on entire
648     # classes, which `skipIf` explicitly forbids.
649     return unittest2.skipIf(lldbplatformutil.getPlatform() in oslist,
650                             "skip on %s" % (", ".join(oslist)))
651
652
653 def skipUnlessPlatform(oslist):
654     """Decorate the item to skip tests unless running on one of the listed platforms."""
655     # This decorator cannot be ported to `skipIf` yet because it is used on entire
656     # classes, which `skipIf` explicitly forbids.
657     return unittest2.skipUnless(lldbplatformutil.getPlatform() in oslist,
658                                 "requires one of %s" % (", ".join(oslist)))
659
660 def skipUnlessArch(arch):
661     """Decorate the item to skip tests unless running on the specified architecture."""
662
663     def arch_doesnt_match(self):
664         target_arch = self.getArchitecture()
665         if arch != target_arch:
666             return "Test only runs on " + arch + ", but target arch is " + target_arch
667         return None
668
669     return skipTestIfFn(arch_doesnt_match)
670
671 def skipIfTargetAndroid(bugnumber=None, api_levels=None, archs=None):
672     """Decorator to skip tests when the target is Android.
673
674     Arguments:
675         api_levels - The API levels for which the test should be skipped. If
676             it is None, then the test will be skipped for all API levels.
677         arch - A sequence of architecture names specifying the architectures
678             for which a test is skipped. None means all architectures.
679     """
680     return skipTestIfFn(
681         _skip_for_android(
682             "skipping for android",
683             api_levels,
684             archs),
685         bugnumber)
686
687 def skipUnlessSupportedTypeAttribute(attr):
688     """Decorate the item to skip test unless Clang supports type __attribute__(attr)."""
689     def compiler_doesnt_support_struct_attribute(self):
690         compiler_path = self.getCompiler()
691         f = tempfile.NamedTemporaryFile()
692         cmd = [self.getCompiler(), "-x", "c++", "-c", "-o", f.name, "-"]
693         p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
694         stdout, stderr = p.communicate('struct __attribute__((%s)) Test {};'%attr)
695         if attr in stderr:
696             return "Compiler does not support attribute %s"%(attr)
697         return None
698     return skipTestIfFn(compiler_doesnt_support_struct_attribute)
699
700 def skipUnlessHasCallSiteInfo(func):
701     """Decorate the function to skip testing unless call site info from clang is available."""
702
703     def is_compiler_clang_with_call_site_info(self):
704         compiler_path = self.getCompiler()
705         compiler = os.path.basename(compiler_path)
706         if not compiler.startswith("clang"):
707             return "Test requires clang as compiler"
708
709         f = tempfile.NamedTemporaryFile()
710         cmd = "echo 'int main() {}' | " \
711               "%s -g -glldb -O1 -S -emit-llvm -x c -o %s -" % (compiler_path, f.name)
712         if os.popen(cmd).close() is not None:
713             return "Compiler can't compile with call site info enabled"
714
715         with open(f.name, 'r') as ir_output_file:
716             buf = ir_output_file.read()
717
718         if 'DIFlagAllCallsDescribed' not in buf:
719             return "Compiler did not introduce DIFlagAllCallsDescribed IR flag"
720
721         return None
722     return skipTestIfFn(is_compiler_clang_with_call_site_info)(func)
723
724 def skipUnlessThreadSanitizer(func):
725     """Decorate the item to skip test unless Clang -fsanitize=thread is supported."""
726
727     def is_compiler_clang_with_thread_sanitizer(self):
728         if is_running_under_asan():
729             return "Thread sanitizer tests are disabled when runing under ASAN"
730
731         compiler_path = self.getCompiler()
732         compiler = os.path.basename(compiler_path)
733         if not compiler.startswith("clang"):
734             return "Test requires clang as compiler"
735         if lldbplatformutil.getPlatform() == 'windows':
736             return "TSAN tests not compatible with 'windows'"
737         # rdar://28659145 - TSAN tests don't look like they're supported on i386
738         if self.getArchitecture() == 'i386' and platform.system() == 'Darwin':
739             return "TSAN tests not compatible with i386 targets"
740         f = tempfile.NamedTemporaryFile()
741         cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name)
742         if os.popen(cmd).close() is not None:
743             return None  # The compiler cannot compile at all, let's *not* skip the test
744         cmd = "echo 'int main() {}' | %s -fsanitize=thread -x c -o %s -" % (compiler_path, f.name)
745         if os.popen(cmd).close() is not None:
746             return "Compiler cannot compile with -fsanitize=thread"
747         return None
748     return skipTestIfFn(is_compiler_clang_with_thread_sanitizer)(func)
749
750 def skipUnlessUndefinedBehaviorSanitizer(func):
751     """Decorate the item to skip test unless -fsanitize=undefined is supported."""
752
753     def is_compiler_clang_with_ubsan(self):
754         if is_running_under_asan():
755             return "Undefined behavior sanitizer tests are disabled when runing under ASAN"
756
757         # Write out a temp file which exhibits UB.
758         inputf = tempfile.NamedTemporaryFile(suffix='.c', mode='w')
759         inputf.write('int main() { int x = 0; return x / x; }\n')
760         inputf.flush()
761
762         # We need to write out the object into a named temp file for inspection.
763         outputf = tempfile.NamedTemporaryFile()
764
765         # Try to compile with ubsan turned on.
766         cmd = '%s -fsanitize=undefined %s -o %s' % (self.getCompiler(), inputf.name, outputf.name)
767         if os.popen(cmd).close() is not None:
768             return "Compiler cannot compile with -fsanitize=undefined"
769
770         # Check that we actually see ubsan instrumentation in the binary.
771         cmd = 'nm %s' % outputf.name
772         with os.popen(cmd) as nm_output:
773             if '___ubsan_handle_divrem_overflow' not in nm_output.read():
774                 return "Division by zero instrumentation is missing"
775
776         # Find the ubsan dylib.
777         # FIXME: This check should go away once compiler-rt gains support for __ubsan_on_report.
778         cmd = '%s -fsanitize=undefined -x c - -o - -### 2>&1' % self.getCompiler()
779         with os.popen(cmd) as cc_output:
780             driver_jobs = cc_output.read()
781             m = re.search(r'"([^"]+libclang_rt.ubsan_osx_dynamic.dylib)"', driver_jobs)
782             if not m:
783                 return "Could not find the ubsan dylib used by the driver"
784             ubsan_dylib = m.group(1)
785
786         # Check that the ubsan dylib has special monitor hooks.
787         cmd = 'nm -gU %s' % ubsan_dylib
788         with os.popen(cmd) as nm_output:
789             syms = nm_output.read()
790             if '___ubsan_on_report' not in syms:
791                 return "Missing ___ubsan_on_report"
792             if '___ubsan_get_current_report_data' not in syms:
793                 return "Missing ___ubsan_get_current_report_data"
794
795         # OK, this dylib + compiler works for us.
796         return None
797
798     return skipTestIfFn(is_compiler_clang_with_ubsan)(func)
799
800 def is_running_under_asan():
801     if ('ASAN_OPTIONS' in os.environ):
802         return "ASAN unsupported"
803     return None
804
805 def skipUnlessAddressSanitizer(func):
806     """Decorate the item to skip test unless Clang -fsanitize=thread is supported."""
807
808     def is_compiler_with_address_sanitizer(self):
809         # Also don't run tests that use address sanitizer inside an
810         # address-sanitized LLDB. The tests don't support that
811         # configuration.
812         if is_running_under_asan():
813             return "Address sanitizer tests are disabled when runing under ASAN"
814
815         compiler_path = self.getCompiler()
816         compiler = os.path.basename(compiler_path)
817         f = tempfile.NamedTemporaryFile()
818         if lldbplatformutil.getPlatform() == 'windows':
819             return "ASAN tests not compatible with 'windows'"
820         cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name)
821         if os.popen(cmd).close() is not None:
822             return None  # The compiler cannot compile at all, let's *not* skip the test
823         cmd = "echo 'int main() {}' | %s -fsanitize=address -x c -o %s -" % (compiler_path, f.name)
824         if os.popen(cmd).close() is not None:
825             return "Compiler cannot compile with -fsanitize=address"
826         return None
827     return skipTestIfFn(is_compiler_with_address_sanitizer)(func)
828
829 def skipIfAsan(func):
830     """Skip this test if the environment is set up to run LLDB *itself* under ASAN."""
831     return skipTestIfFn(is_running_under_asan)(func)
832
833 def _get_bool_config(key, fail_value = True):
834     """
835     Returns the current LLDB's build config value.
836     :param key The key to lookup in LLDB's build configuration.
837     :param fail_value The error value to return when the key can't be found.
838            Defaults to true so that if an unknown key is lookup up we rather
839            enable more tests (that then fail) than silently skipping them.
840     """
841     config = lldb.SBDebugger.GetBuildConfiguration()
842     value_node = config.GetValueForKey(key)
843     return value_node.GetValueForKey("value").GetBooleanValue(fail_value)
844
845 def _get_bool_config_skip_if_decorator(key):
846     have = _get_bool_config(key)
847     return unittest2.skipIf(not have, "requires " + key)
848
849 def skipIfCursesSupportMissing(func):
850     return _get_bool_config_skip_if_decorator("curses")(func)
851
852 def skipIfXmlSupportMissing(func):
853     return _get_bool_config_skip_if_decorator("xml")(func)
854
855 def skipIfEditlineSupportMissing(func):
856     return _get_bool_config_skip_if_decorator("editline")(func)
857
858 def skipIfLLVMTargetMissing(target):
859     config = lldb.SBDebugger.GetBuildConfiguration()
860     targets = config.GetValueForKey("targets").GetValueForKey("value")
861     found = False
862     for i in range(targets.GetSize()):
863         if targets.GetItemAtIndex(i).GetStringValue(99) == target:
864             found = True
865             break
866
867     return unittest2.skipIf(not found, "requires " + target)
868
869 # Call sysctl on darwin to see if a specified hardware feature is available on this machine.
870 def skipUnlessFeature(feature):
871     def is_feature_enabled(self):
872         if platform.system() == 'Darwin':
873             try:
874                 DEVNULL = open(os.devnull, 'w')
875                 output = subprocess.check_output(["/usr/sbin/sysctl", feature], stderr=DEVNULL).decode("utf-8")
876                 # If 'feature: 1' was output, then this feature is available and
877                 # the test should not be skipped.
878                 if re.match('%s: 1\s*' % feature, output):
879                     return None
880                 else:
881                     return "%s is not supported on this system." % feature
882             except subprocess.CalledProcessError:
883                 return "%s is not supported on this system." % feature
884     return skipTestIfFn(is_feature_enabled)
885
886 def skipIfReproducer(func):
887     """Skip this test if the environment is set up to run LLDB with reproducers."""
888     return unittest2.skipIf(
889         configuration.capture_path or configuration.replay_path,
890         "reproducers unsupported")(func)