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