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