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