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