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