1from __future__ import absolute_import
2from __future__ import print_function
3
4# System modules
5from distutils.version import LooseVersion, StrictVersion
6from functools import wraps
7import os
8import re
9import sys
10import tempfile
11
12# Third-party modules
13import six
14import unittest2
15
16# LLDB modules
17import use_lldb_suite
18
19import lldb
20from . import configuration
21from . import test_categories
22from lldbsuite.test_event.event_builder import EventBuilder
23from lldbsuite.support import funcutils
24from lldbsuite.test import lldbplatform
25from lldbsuite.test import lldbplatformutil
26
27class DecorateMode:
28    Skip, Xfail = range(2)
29
30
31# You can use no_match to reverse the test of the conditional that is used to match keyword
32# arguments in the skip / xfail decorators.  If oslist=["windows", "linux"] skips windows
33# and linux, oslist=no_match(["windows", "linux"]) skips *unless* windows or linux.
34class no_match:
35    def __init__(self, item):
36        self.item = item
37
38def _check_expected_version(comparison, expected, actual):
39    def fn_leq(x,y): return x <= y
40    def fn_less(x,y): return x < y
41    def fn_geq(x,y): return x >= y
42    def fn_greater(x,y): return x > y
43    def fn_eq(x,y): return x == y
44    def fn_neq(x,y): return x != y
45
46    op_lookup = {
47        "==": fn_eq,
48        "=": fn_eq,
49        "!=": fn_neq,
50        "<>": fn_neq,
51        ">": fn_greater,
52        "<": fn_less,
53        ">=": fn_geq,
54        "<=": fn_leq
55        }
56    expected_str = '.'.join([str(x) for x in expected])
57    actual_str = '.'.join([str(x) for x in actual])
58
59    return op_lookup[comparison](LooseVersion(actual_str), LooseVersion(expected_str))
60
61def _match_decorator_property(expected, actual):
62    if actual is None or expected is None:
63        return True
64
65    if isinstance(expected, no_match):
66        return not _match_decorator_property(expected.item, actual)
67    elif isinstance(expected, (re._pattern_type,)+six.string_types):
68        return re.search(expected, actual) is not None
69    elif hasattr(expected, "__iter__"):
70        return any([x is not None and _match_decorator_property(x, actual) for x in expected])
71    else:
72        return expected == actual
73
74def expectedFailure(expected_fn, bugnumber=None):
75    def expectedFailure_impl(func):
76        if isinstance(func, type) and issubclass(func, unittest2.TestCase):
77            raise Exception("Decorator can only be used to decorate a test method")
78        @wraps(func)
79        def wrapper(*args, **kwargs):
80            self = args[0]
81            if funcutils.requires_self(expected_fn):
82                xfail_reason = expected_fn(self)
83            else:
84                xfail_reason = expected_fn()
85            if xfail_reason is not None:
86                if configuration.results_formatter_object is not None:
87                    # Mark this test as expected to fail.
88                    configuration.results_formatter_object.handle_event(
89                        EventBuilder.event_for_mark_test_expected_failure(self))
90                xfail_func = unittest2.expectedFailure(func)
91                xfail_func(*args, **kwargs)
92            else:
93                func(*args, **kwargs)
94        return wrapper
95    # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows)
96    # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])).  When called
97    # the first way, the first argument will be the actual function because decorators are
98    # weird like that.  So this is basically a check that says "which syntax was the original
99    # function decorated with?"
100    if six.callable(bugnumber):
101        return expectedFailure_impl(bugnumber)
102    else:
103        return expectedFailure_impl
104
105def skipTestIfFn(expected_fn, bugnumber=None):
106    def skipTestIfFn_impl(func):
107        if isinstance(func, type) and issubclass(func, unittest2.TestCase):
108            raise Exception("@skipTestIfFn can only be used to decorate a test method")
109
110        @wraps(func)
111        def wrapper(*args, **kwargs):
112            self = args[0]
113            if funcutils.requires_self(expected_fn):
114                reason = expected_fn(self)
115            else:
116                reason = expected_fn()
117
118            if reason is not None:
119               self.skipTest(reason)
120            else:
121                func(*args, **kwargs)
122        return wrapper
123
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 "how was the decorator used"
128    if six.callable(bugnumber):
129        return skipTestIfFn_impl(bugnumber)
130    else:
131        return skipTestIfFn_impl
132
133def _decorateTest(mode,
134                 bugnumber=None, oslist=None, hostoslist=None,
135                 compiler=None, compiler_version=None,
136                 archs=None, triple=None,
137                 debug_info=None,
138                 swig_version=None, py_version=None,
139                 remote=None):
140    def fn(self):
141        skip_for_os = _match_decorator_property(lldbplatform.translate(oslist), self.getPlatform())
142        skip_for_hostos = _match_decorator_property(lldbplatform.translate(hostoslist), lldbplatformutil.getHostPlatform())
143        skip_for_compiler = _match_decorator_property(compiler, self.getCompiler()) and self.expectedCompilerVersion(compiler_version)
144        skip_for_arch = _match_decorator_property(archs, self.getArchitecture())
145        skip_for_debug_info = _match_decorator_property(debug_info, self.debug_info)
146        skip_for_triple = _match_decorator_property(triple, lldb.DBG.GetSelectedPlatform().GetTriple())
147        skip_for_remote = _match_decorator_property(remote, lldb.remote_platform is not None)
148
149        skip_for_swig_version = (swig_version is None) or (not hasattr(lldb, 'swig_version')) or (_check_expected_version(swig_version[0], swig_version[1], lldb.swig_version))
150        skip_for_py_version = (py_version is None) or _check_expected_version(py_version[0], py_version[1], sys.version_info)
151
152        # For the test to be skipped, all specified (e.g. not None) parameters must be True.
153        # An unspecified parameter means "any", so those are marked skip by default.  And we skip
154        # the final test if all conditions are True.
155        conditions = [(oslist, skip_for_os, "target o/s"),
156                      (hostoslist, skip_for_hostos, "host o/s"),
157                      (compiler, skip_for_compiler, "compiler or version"),
158                      (archs, skip_for_arch, "architecture"),
159                      (debug_info, skip_for_debug_info, "debug info format"),
160                      (triple, skip_for_triple, "target triple"),
161                      (swig_version, skip_for_swig_version, "swig version"),
162                      (py_version, skip_for_py_version, "python version"),
163                      (remote, skip_for_remote, "platform locality (remote/local)")]
164        reasons = []
165        final_skip_result = True
166        for this_condition in conditions:
167            final_skip_result = final_skip_result and this_condition[1]
168            if this_condition[0] is not None and this_condition[1]:
169                reasons.append(this_condition[2])
170        reason_str = None
171        if final_skip_result:
172            mode_str = {DecorateMode.Skip : "skipping", DecorateMode.Xfail : "xfailing"}[mode]
173            if len(reasons) > 0:
174                reason_str = ",".join(reasons)
175                reason_str = "{} due to the following parameter(s): {}".format(mode_str, reason_str)
176            else:
177                reason_str = "{} unconditionally"
178            if bugnumber is not None and not six.callable(bugnumber):
179                reason_str = reason_str + " [" + str(bugnumber) + "]"
180        return reason_str
181
182    if mode == DecorateMode.Skip:
183        return skipTestIfFn(fn, bugnumber)
184    elif mode == DecorateMode.Xfail:
185        return expectedFailure(fn, bugnumber)
186    else:
187        return None
188
189# provide a function to xfail on defined oslist, compiler version, and archs
190# if none is specified for any argument, that argument won't be checked and thus means for all
191# for example,
192# @expectedFailureAll, xfail for all platform/compiler/arch,
193# @expectedFailureAll(compiler='gcc'), xfail for gcc on all platform/architecture
194# @expectedFailureAll(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), xfail for gcc>=4.9 on linux with i386
195def expectedFailureAll(bugnumber=None,
196                       oslist=None, hostoslist=None,
197                       compiler=None, compiler_version=None,
198                       archs=None, triple=None,
199                       debug_info=None,
200                       swig_version=None, py_version=None,
201                       remote=None):
202    return _decorateTest(DecorateMode.Xfail,
203                        bugnumber=bugnumber,
204                        oslist=oslist, hostoslist=hostoslist,
205                        compiler=compiler, compiler_version=compiler_version,
206                        archs=archs, triple=triple,
207                        debug_info=debug_info,
208                        swig_version=swig_version, py_version=py_version,
209                        remote=remote)
210
211
212# provide a function to skip on defined oslist, compiler version, and archs
213# if none is specified for any argument, that argument won't be checked and thus means for all
214# for example,
215# @skipIf, skip for all platform/compiler/arch,
216# @skipIf(compiler='gcc'), skip for gcc on all platform/architecture
217# @skipIf(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), skip for gcc>=4.9 on linux with i386
218def skipIf(bugnumber=None,
219           oslist=None, hostoslist=None,
220           compiler=None, compiler_version=None,
221           archs=None, triple=None,
222           debug_info=None,
223           swig_version=None, py_version=None,
224           remote=None):
225    return _decorateTest(DecorateMode.Skip,
226                        bugnumber=bugnumber,
227                        oslist=oslist, hostoslist=hostoslist,
228                        compiler=compiler, compiler_version=compiler_version,
229                        archs=archs, triple=triple,
230                        debug_info=debug_info,
231                        swig_version=swig_version, py_version=py_version,
232                        remote=remote)
233
234def _skip_for_android(reason, api_levels, archs):
235    def impl(obj):
236        result = lldbplatformutil.match_android_device(obj.getArchitecture(), valid_archs=archs, valid_api_levels=api_levels)
237        return reason if result else None
238    return impl
239
240def add_test_categories(cat):
241    """Add test categories to a TestCase method"""
242    cat = test_categories.validate(cat, True)
243    def impl(func):
244        if isinstance(func, type) and issubclass(func, unittest2.TestCase):
245            raise Exception("@add_test_categories can only be used to decorate a test method")
246        if hasattr(func, "categories"):
247            cat.extend(func.categories)
248        func.categories = cat
249        return func
250
251    return impl
252
253def benchmarks_test(func):
254    """Decorate the item as a benchmarks test."""
255    def should_skip_benchmarks_test():
256        return "benchmarks test"
257
258    # Mark this function as such to separate them from the regular tests.
259    result = skipTestIfFn(should_skip_benchmarks_test)(func)
260    result.__benchmarks_test__ = True
261    return result
262
263def no_debug_info_test(func):
264    """Decorate the item as a test what don't use any debug info. If this annotation is specified
265       then the test runner won't generate a separate test for each debug info format. """
266    if isinstance(func, type) and issubclass(func, unittest2.TestCase):
267        raise Exception("@no_debug_info_test can only be used to decorate a test method")
268    @wraps(func)
269    def wrapper(self, *args, **kwargs):
270        return func(self, *args, **kwargs)
271
272    # Mark this function as such to separate them from the regular tests.
273    wrapper.__no_debug_info_test__ = True
274    return wrapper
275
276def debugserver_test(func):
277    """Decorate the item as a debugserver test."""
278    def should_skip_debugserver_test():
279        return "debugserver tests" if configuration.dont_do_debugserver_test else None
280    return skipTestIfFn(should_skip_debugserver_test)(func)
281
282def llgs_test(func):
283    """Decorate the item as a lldb-server test."""
284    def should_skip_llgs_tests():
285        return "llgs tests" if configuration.dont_do_llgs_test else None
286    return skipTestIfFn(should_skip_llgs_tests)(func)
287
288def not_remote_testsuite_ready(func):
289    """Decorate the item as a test which is not ready yet for remote testsuite."""
290    def is_remote():
291        return "Not ready for remote testsuite" if lldb.remote_platform else None
292    return skipTestIfFn(is_remote)(func)
293
294def expectedFailureOS(oslist, bugnumber=None, compilers=None, debug_info=None, archs=None):
295    return expectedFailureAll(oslist=oslist, bugnumber=bugnumber, compiler=compilers, archs=archs, debug_info=debug_info)
296
297def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None):
298    # For legacy reasons, we support both "darwin" and "macosx" as OS X triples.
299    return expectedFailureOS(lldbplatform.darwin_all, bugnumber, compilers, debug_info=debug_info)
300
301def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None):
302    """ Mark a test as xfail for Android.
303
304    Arguments:
305        bugnumber - The LLVM pr associated with the problem.
306        api_levels - A sequence of numbers specifying the Android API levels
307            for which a test is expected to fail. None means all API level.
308        arch - A sequence of architecture names specifying the architectures
309            for which a test is expected to fail. None means all architectures.
310    """
311    return expectedFailure(_skip_for_android("xfailing on android", api_levels, archs), bugnumber)
312
313# Flakey tests get two chances to run. If they fail the first time round, the result formatter
314# makes sure it is run one more time.
315def expectedFlakey(expected_fn, bugnumber=None):
316    def expectedFailure_impl(func):
317        @wraps(func)
318        def wrapper(*args, **kwargs):
319            self = args[0]
320            if expected_fn(self):
321                # Send event marking test as explicitly eligible for rerunning.
322                if configuration.results_formatter_object is not None:
323                    # Mark this test as rerunnable.
324                    configuration.results_formatter_object.handle_event(
325                        EventBuilder.event_for_mark_test_rerun_eligible(self))
326            func(*args, **kwargs)
327        return wrapper
328    # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows)
329    # or with arguments (e.g. @expectedFailureWindows(compilers=['gcc'])).  When called
330    # the first way, the first argument will be the actual function because decorators are
331    # weird like that.  So this is basically a check that says "which syntax was the original
332    # function decorated with?"
333    if six.callable(bugnumber):
334        return expectedFailure_impl(bugnumber)
335    else:
336        return expectedFailure_impl
337
338def expectedFlakeyDwarf(bugnumber=None):
339    def fn(self):
340        return self.debug_info == "dwarf"
341    return expectedFlakey(fn, bugnumber)
342
343def expectedFlakeyDsym(bugnumber=None):
344    def fn(self):
345        return self.debug_info == "dwarf"
346    return expectedFlakey(fn, bugnumber)
347
348def expectedFlakeyOS(oslist, bugnumber=None, compilers=None):
349    def fn(self):
350        return (self.getPlatform() in oslist and
351                self.expectedCompiler(compilers))
352    return expectedFlakey(fn, bugnumber)
353
354def expectedFlakeyDarwin(bugnumber=None, compilers=None):
355    # For legacy reasons, we support both "darwin" and "macosx" as OS X triples.
356    return expectedFlakeyOS(lldbplatformutil.getDarwinOSTriples(), bugnumber, compilers)
357
358def expectedFlakeyFreeBSD(bugnumber=None, compilers=None):
359    return expectedFlakeyOS(['freebsd'], bugnumber, compilers)
360
361def expectedFlakeyLinux(bugnumber=None, compilers=None):
362    return expectedFlakeyOS(['linux'], bugnumber, compilers)
363
364def expectedFlakeyNetBSD(bugnumber=None, compilers=None):
365    return expectedFlakeyOS(['netbsd'], bugnumber, compilers)
366
367def expectedFlakeyCompiler(compiler, compiler_version=None, bugnumber=None):
368    if compiler_version is None:
369        compiler_version=['=', None]
370    def fn(self):
371        return compiler in self.getCompiler() and self.expectedCompilerVersion(compiler_version)
372    return expectedFlakey(fn, bugnumber)
373
374# @expectedFlakeyClang('bugnumber', ['<=', '3.4'])
375def expectedFlakeyClang(bugnumber=None, compiler_version=None):
376    return expectedFlakeyCompiler('clang', compiler_version, bugnumber)
377
378# @expectedFlakeyGcc('bugnumber', ['<=', '3.4'])
379def expectedFlakeyGcc(bugnumber=None, compiler_version=None):
380    return expectedFlakeyCompiler('gcc', compiler_version, bugnumber)
381
382def expectedFlakeyAndroid(bugnumber=None, api_levels=None, archs=None):
383    return expectedFlakey(_skip_for_android("flakey on android", api_levels, archs), bugnumber)
384
385def skipIfRemote(func):
386    """Decorate the item to skip tests if testing remotely."""
387    def is_remote():
388        return "skip on remote platform" if lldb.remote_platform else None
389    return skipTestIfFn(is_remote)(func)
390
391def skipIfRemoteDueToDeadlock(func):
392    """Decorate the item to skip tests if testing remotely due to the test deadlocking."""
393    def is_remote():
394        return "skip on remote platform (deadlocks)" if lldb.remote_platform else None
395    return skipTestIfFn(is_remote)(func)
396
397def skipIfNoSBHeaders(func):
398    """Decorate the item to mark tests that should be skipped when LLDB is built with no SB API headers."""
399    def are_sb_headers_missing():
400        if lldbplatformutil.getHostPlatform() == 'darwin':
401            header = os.path.join(os.environ["LLDB_LIB_DIR"], 'LLDB.framework', 'Versions','Current','Headers','LLDB.h')
402        else:
403            header = os.path.join(os.environ["LLDB_SRC"], "include", "lldb", "API", "LLDB.h")
404        if not os.path.exists(header):
405            return "skip because LLDB.h header not found"
406        return None
407
408    return skipTestIfFn(are_sb_headers_missing)(func)
409
410def skipIfiOSSimulator(func):
411    """Decorate the item to skip tests that should be skipped on the iOS Simulator."""
412    def is_ios_simulator():
413        return "skip on the iOS Simulator" if configuration.lldb_platform_name == 'ios-simulator' else None
414    return skipTestIfFn(is_ios_simulator)(func)
415
416def skipIfFreeBSD(func):
417    """Decorate the item to skip tests that should be skipped on FreeBSD."""
418    return skipIfPlatform(["freebsd"])(func)
419
420def skipIfNetBSD(func):
421    """Decorate the item to skip tests that should be skipped on NetBSD."""
422    return skipIfPlatform(["netbsd"])(func)
423
424def skipIfDarwin(func):
425    """Decorate the item to skip tests that should be skipped on Darwin."""
426    return skipIfPlatform(lldbplatform.translate(lldbplatform.darwin_all))(func)
427
428def skipIfLinux(func):
429    """Decorate the item to skip tests that should be skipped on Linux."""
430    return skipIfPlatform(["linux"])(func)
431
432def skipIfWindows(func):
433    """Decorate the item to skip tests that should be skipped on Windows."""
434    return skipIfPlatform(["windows"])(func)
435
436def skipUnlessWindows(func):
437    """Decorate the item to skip tests that should be skipped on any non-Windows platform."""
438    return skipUnlessPlatform(["windows"])(func)
439
440def skipUnlessDarwin(func):
441    """Decorate the item to skip tests that should be skipped on any non Darwin platform."""
442    return skipUnlessPlatform(lldbplatformutil.getDarwinOSTriples())(func)
443
444def skipUnlessGoInstalled(func):
445    """Decorate the item to skip tests when no Go compiler is available."""
446    def is_go_missing(self):
447        compiler = self.getGoCompilerVersion()
448        if not compiler:
449            return "skipping because go compiler not found"
450        match_version = re.search(r"(\d+\.\d+(\.\d+)?)", compiler)
451        if not match_version:
452            # Couldn't determine version.
453            return "skipping because go version could not be parsed out of {}".format(compiler)
454        else:
455            min_strict_version = StrictVersion("1.4.0")
456            compiler_strict_version = StrictVersion(match_version.group(1))
457            if compiler_strict_version < min_strict_version:
458                return "skipping because available version ({}) does not meet minimum required version ({})".format(
459                    compiler_strict_version, min_strict_version)
460        return None
461    return skipTestIfFn(is_go_missing)(func)
462
463def skipIfHostIncompatibleWithRemote(func):
464    """Decorate the item to skip tests if binaries built on this host are incompatible."""
465    def is_host_incompatible_with_remote(self):
466        host_arch = self.getLldbArchitecture()
467        host_platform = lldbplatformutil.getHostPlatform()
468        target_arch = self.getArchitecture()
469        target_platform = 'darwin' if self.platformIsDarwin() else self.getPlatform()
470        if not (target_arch == 'x86_64' and host_arch == 'i386') and host_arch != target_arch:
471            return "skipping because target %s is not compatible with host architecture %s" % (target_arch, host_arch)
472        elif target_platform != host_platform:
473            return "skipping because target is %s but host is %s" % (target_platform, host_platform)
474        return None
475    return skipTestIfFn(is_host_incompatible_with_remote)(func)
476
477def skipIfPlatform(oslist):
478    """Decorate the item to skip tests if running on one of the listed platforms."""
479    # This decorator cannot be ported to `skipIf` yet because it is used on entire
480    # classes, which `skipIf` explicitly forbids.
481    return unittest2.skipIf(lldbplatformutil.getPlatform() in oslist,
482                            "skip on %s" % (", ".join(oslist)))
483
484def skipUnlessPlatform(oslist):
485    """Decorate the item to skip tests unless running on one of the listed platforms."""
486    # This decorator cannot be ported to `skipIf` yet because it is used on entire
487    # classes, which `skipIf` explicitly forbids.
488    return unittest2.skipUnless(lldbplatformutil.getPlatform() in oslist,
489                                "requires on of %s" % (", ".join(oslist)))
490
491def skipIfTargetAndroid(api_levels=None, archs=None):
492    """Decorator to skip tests when the target is Android.
493
494    Arguments:
495        api_levels - The API levels for which the test should be skipped. If
496            it is None, then the test will be skipped for all API levels.
497        arch - A sequence of architecture names specifying the architectures
498            for which a test is skipped. None means all architectures.
499    """
500    return skipTestIfFn(_skip_for_android("skipping for android", api_levels, archs))
501
502def skipUnlessCompilerRt(func):
503    """Decorate the item to skip tests if testing remotely."""
504    def is_compiler_rt_missing():
505        compilerRtPath = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "llvm","projects","compiler-rt")
506        return "compiler-rt not found" if not os.path.exists(compilerRtPath) else None
507    return skipTestIfFn(is_compiler_rt_missing)(func)
508
509def skipUnlessThreadSanitizer(func):
510    """Decorate the item to skip test unless Clang -fsanitize=thread is supported."""
511    def is_compiler_clang_with_thread_sanitizer(self):
512        compiler_path = self.getCompiler()
513        compiler = os.path.basename(compiler_path)
514        if not compiler.startswith("clang"):
515            return "Test requires clang as compiler"
516        f = tempfile.NamedTemporaryFile()
517        cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name)
518        if os.popen(cmd).close() != None:
519            return None  # The compiler cannot compile at all, let's *not* skip the test
520        cmd = "echo 'int main() {}' | %s -fsanitize=thread -x c -o %s -" % (compiler_path, f.name)
521        if os.popen(cmd).close() != None:
522            return "Compiler cannot compile with -fsanitize=thread"
523        return None
524    return skipTestIfFn(is_compiler_clang_with_thread_sanitizer)(func)
525