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 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    def is_remote():
505        return "skip on remote platform" if lldb.remote_platform else None
506    return skipTestIfFn(is_remote)(func)
507
508
509def skipIfNoSBHeaders(func):
510    """Decorate the item to mark tests that should be skipped when LLDB is built with no SB API headers."""
511    def are_sb_headers_missing():
512        if lldbplatformutil.getHostPlatform() == 'darwin':
513            header = os.path.join(
514                os.environ["LLDB_LIB_DIR"],
515                'LLDB.framework',
516                'Versions',
517                'Current',
518                'Headers',
519                'LLDB.h')
520            if os.path.exists(header):
521                return None
522
523        header = os.path.join(
524            os.environ["LLDB_SRC"],
525            "include",
526            "lldb",
527            "API",
528            "LLDB.h")
529        if not os.path.exists(header):
530            return "skip because LLDB.h header not found"
531        return None
532
533    return skipTestIfFn(are_sb_headers_missing)(func)
534
535
536def skipIfiOSSimulator(func):
537    """Decorate the item to skip tests that should be skipped on the iOS Simulator."""
538    def is_ios_simulator():
539        return "skip on the iOS Simulator" if configuration.lldb_platform_name == 'ios-simulator' else None
540    return skipTestIfFn(is_ios_simulator)(func)
541
542def skipIfiOS(func):
543    return skipIfPlatform(["ios"])(func)
544
545def skipIftvOS(func):
546    return skipIfPlatform(["tvos"])(func)
547
548def skipIfwatchOS(func):
549    return skipIfPlatform(["watchos"])(func)
550
551def skipIfbridgeOS(func):
552    return skipIfPlatform(["bridgeos"])(func)
553
554def skipIfDarwinEmbedded(func):
555    """Decorate the item to skip tests that should be skipped on Darwin armv7/arm64 targets."""
556    return skipIfPlatform(
557        lldbplatform.translate(
558            lldbplatform.darwin_embedded))(func)
559
560def skipIfFreeBSD(func):
561    """Decorate the item to skip tests that should be skipped on FreeBSD."""
562    return skipIfPlatform(["freebsd"])(func)
563
564
565def skipIfNetBSD(func):
566    """Decorate the item to skip tests that should be skipped on NetBSD."""
567    return skipIfPlatform(["netbsd"])(func)
568
569
570def skipIfDarwin(func):
571    """Decorate the item to skip tests that should be skipped on Darwin."""
572    return skipIfPlatform(
573        lldbplatform.translate(
574            lldbplatform.darwin_all))(func)
575
576
577def skipIfLinux(func):
578    """Decorate the item to skip tests that should be skipped on Linux."""
579    return skipIfPlatform(["linux"])(func)
580
581
582def skipIfWindows(func):
583    """Decorate the item to skip tests that should be skipped on Windows."""
584    return skipIfPlatform(["windows"])(func)
585
586
587def skipUnlessWindows(func):
588    """Decorate the item to skip tests that should be skipped on any non-Windows platform."""
589    return skipUnlessPlatform(["windows"])(func)
590
591
592def skipUnlessDarwin(func):
593    """Decorate the item to skip tests that should be skipped on any non Darwin platform."""
594    return skipUnlessPlatform(lldbplatformutil.getDarwinOSTriples())(func)
595
596
597def skipIfHostIncompatibleWithRemote(func):
598    """Decorate the item to skip tests if binaries built on this host are incompatible."""
599
600    def is_host_incompatible_with_remote(self):
601        host_arch = self.getLldbArchitecture()
602        host_platform = lldbplatformutil.getHostPlatform()
603        target_arch = self.getArchitecture()
604        target_platform = 'darwin' if self.platformIsDarwin() else self.getPlatform()
605        if not (target_arch == 'x86_64' and host_arch ==
606                'i386') and host_arch != target_arch:
607            return "skipping because target %s is not compatible with host architecture %s" % (
608                target_arch, host_arch)
609        if target_platform != host_platform:
610            return "skipping because target is %s but host is %s" % (
611                target_platform, host_platform)
612        if lldbplatformutil.match_android_device(target_arch):
613            return "skipping because target is android"
614        return None
615    return skipTestIfFn(is_host_incompatible_with_remote)(func)
616
617
618def skipIfPlatform(oslist):
619    """Decorate the item to skip tests if running on one of the listed platforms."""
620    # This decorator cannot be ported to `skipIf` yet because it is used on entire
621    # classes, which `skipIf` explicitly forbids.
622    return unittest2.skipIf(lldbplatformutil.getPlatform() in oslist,
623                            "skip on %s" % (", ".join(oslist)))
624
625
626def skipUnlessPlatform(oslist):
627    """Decorate the item to skip tests unless running on one of the listed platforms."""
628    # This decorator cannot be ported to `skipIf` yet because it is used on entire
629    # classes, which `skipIf` explicitly forbids.
630    return unittest2.skipUnless(lldbplatformutil.getPlatform() in oslist,
631                                "requires one of %s" % (", ".join(oslist)))
632
633
634def skipIfTargetAndroid(api_levels=None, archs=None):
635    """Decorator to skip tests when the target is Android.
636
637    Arguments:
638        api_levels - The API levels for which the test should be skipped. If
639            it is None, then the test will be skipped for all API levels.
640        arch - A sequence of architecture names specifying the architectures
641            for which a test is skipped. None means all architectures.
642    """
643    return skipTestIfFn(
644        _skip_for_android(
645            "skipping for android",
646            api_levels,
647            archs))
648
649def skipUnlessSupportedTypeAttribute(attr):
650    """Decorate the item to skip test unless Clang supports type __attribute__(attr)."""
651    def compiler_doesnt_support_struct_attribute(self):
652        compiler_path = self.getCompiler()
653        f = tempfile.NamedTemporaryFile()
654        cmd = [self.getCompiler(), "-x", "c++", "-c", "-o", f.name, "-"]
655        p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
656        stdout, stderr = p.communicate('struct __attribute__((%s)) Test {};'%attr)
657        if attr in stderr:
658            return "Compiler does not support attribute %s"%(attr)
659        return None
660    return skipTestIfFn(compiler_doesnt_support_struct_attribute)
661
662def skipUnlessHasCallSiteInfo(func):
663    """Decorate the function to skip testing unless call site info from clang is available."""
664
665    def is_compiler_clang_with_call_site_info(self):
666        compiler_path = self.getCompiler()
667        compiler = os.path.basename(compiler_path)
668        if not compiler.startswith("clang"):
669            return "Test requires clang as compiler"
670
671        f = tempfile.NamedTemporaryFile()
672        cmd = "echo 'int main() {}' | " \
673              "%s -g -glldb -O1 -S -emit-llvm -x c -o %s -" % (compiler_path, f.name)
674        if os.popen(cmd).close() is not None:
675            return "Compiler can't compile with call site info enabled"
676
677        with open(f.name, 'r') as ir_output_file:
678            buf = ir_output_file.read()
679
680        if 'DIFlagAllCallsDescribed' not in buf:
681            return "Compiler did not introduce DIFlagAllCallsDescribed IR flag"
682
683        return None
684    return skipTestIfFn(is_compiler_clang_with_call_site_info)(func)
685
686def skipUnlessThreadSanitizer(func):
687    """Decorate the item to skip test unless Clang -fsanitize=thread is supported."""
688
689    def is_compiler_clang_with_thread_sanitizer(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        if lldbplatformutil.getPlatform() == 'windows':
695            return "TSAN tests not compatible with 'windows'"
696        # rdar://28659145 - TSAN tests don't look like they're supported on i386
697        if self.getArchitecture() == 'i386' and platform.system() == 'Darwin':
698            return "TSAN tests not compatible with i386 targets"
699        f = tempfile.NamedTemporaryFile()
700        cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name)
701        if os.popen(cmd).close() is not None:
702            return None  # The compiler cannot compile at all, let's *not* skip the test
703        cmd = "echo 'int main() {}' | %s -fsanitize=thread -x c -o %s -" % (compiler_path, f.name)
704        if os.popen(cmd).close() is not None:
705            return "Compiler cannot compile with -fsanitize=thread"
706        return None
707    return skipTestIfFn(is_compiler_clang_with_thread_sanitizer)(func)
708
709def skipUnlessUndefinedBehaviorSanitizer(func):
710    """Decorate the item to skip test unless -fsanitize=undefined is supported."""
711
712    def is_compiler_clang_with_ubsan(self):
713        # Write out a temp file which exhibits UB.
714        inputf = tempfile.NamedTemporaryFile(suffix='.c', mode='w')
715        inputf.write('int main() { int x = 0; return x / x; }\n')
716        inputf.flush()
717
718        # We need to write out the object into a named temp file for inspection.
719        outputf = tempfile.NamedTemporaryFile()
720
721        # Try to compile with ubsan turned on.
722        cmd = '%s -fsanitize=undefined %s -o %s' % (self.getCompiler(), inputf.name, outputf.name)
723        if os.popen(cmd).close() is not None:
724            return "Compiler cannot compile with -fsanitize=undefined"
725
726        # Check that we actually see ubsan instrumentation in the binary.
727        cmd = 'nm %s' % outputf.name
728        with os.popen(cmd) as nm_output:
729            if '___ubsan_handle_divrem_overflow' not in nm_output.read():
730                return "Division by zero instrumentation is missing"
731
732        # Find the ubsan dylib.
733        # FIXME: This check should go away once compiler-rt gains support for __ubsan_on_report.
734        cmd = '%s -fsanitize=undefined -x c - -o - -### 2>&1' % self.getCompiler()
735        with os.popen(cmd) as cc_output:
736            driver_jobs = cc_output.read()
737            m = re.search(r'"([^"]+libclang_rt.ubsan_osx_dynamic.dylib)"', driver_jobs)
738            if not m:
739                return "Could not find the ubsan dylib used by the driver"
740            ubsan_dylib = m.group(1)
741
742        # Check that the ubsan dylib has special monitor hooks.
743        cmd = 'nm -gU %s' % ubsan_dylib
744        with os.popen(cmd) as nm_output:
745            syms = nm_output.read()
746            if '___ubsan_on_report' not in syms:
747                return "Missing ___ubsan_on_report"
748            if '___ubsan_get_current_report_data' not in syms:
749                return "Missing ___ubsan_get_current_report_data"
750
751        # OK, this dylib + compiler works for us.
752        return None
753
754    return skipTestIfFn(is_compiler_clang_with_ubsan)(func)
755
756def skipUnlessAddressSanitizer(func):
757    """Decorate the item to skip test unless Clang -fsanitize=thread is supported."""
758
759    def is_compiler_with_address_sanitizer(self):
760        compiler_path = self.getCompiler()
761        compiler = os.path.basename(compiler_path)
762        f = tempfile.NamedTemporaryFile()
763        if lldbplatformutil.getPlatform() == 'windows':
764            return "ASAN tests not compatible with 'windows'"
765        cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name)
766        if os.popen(cmd).close() is not None:
767            return None  # The compiler cannot compile at all, let's *not* skip the test
768        cmd = "echo 'int main() {}' | %s -fsanitize=address -x c -o %s -" % (compiler_path, f.name)
769        if os.popen(cmd).close() is not None:
770            return "Compiler cannot compile with -fsanitize=address"
771        return None
772    return skipTestIfFn(is_compiler_with_address_sanitizer)(func)
773
774def skipIfXmlSupportMissing(func):
775    config = lldb.SBDebugger.GetBuildConfiguration()
776    xml = config.GetValueForKey("xml")
777
778    fail_value = True # More likely to notice if something goes wrong
779    have_xml = xml.GetValueForKey("value").GetBooleanValue(fail_value)
780    return unittest2.skipIf(not have_xml, "requires xml support")(func)
781
782def skipIfLLVMTargetMissing(target):
783    config = lldb.SBDebugger.GetBuildConfiguration()
784    targets = config.GetValueForKey("targets").GetValueForKey("value")
785    found = False
786    for i in range(targets.GetSize()):
787        if targets.GetItemAtIndex(i).GetStringValue(99) == target:
788            found = True
789            break
790
791    return unittest2.skipIf(not found, "requires " + target)
792
793# Call sysctl on darwin to see if a specified hardware feature is available on this machine.
794def skipUnlessFeature(feature):
795    def is_feature_enabled(self):
796        if platform.system() == 'Darwin':
797            try:
798                DEVNULL = open(os.devnull, 'w')
799                output = subprocess.check_output(["/usr/sbin/sysctl", feature], stderr=DEVNULL)
800                # If 'feature: 1' was output, then this feature is available and
801                # the test should not be skipped.
802                if re.match('%s: 1\s*' % feature, output):
803                    return None
804                else:
805                    return "%s is not supported on this system." % feature
806            except subprocess.CalledProcessError:
807                return "%s is not supported on this system." % feature
808    return skipTestIfFn(is_feature_enabled)
809