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