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