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