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