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