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