diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:50:09 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:50:09 +0000 | 
| commit | f3fbd1c0586ff6ec7895991e6c28f61a503c36a8 (patch) | |
| tree | 48d008fd3df8c0e73271a4b18474e0aac6dbfe33 /packages/Python/lldbsuite/test/lldbtest.py | |
| parent | 2fc5d2d1dfaf623ce4e24cd8590565902f8c557c (diff) | |
Notes
Diffstat (limited to 'packages/Python/lldbsuite/test/lldbtest.py')
| -rw-r--r-- | packages/Python/lldbsuite/test/lldbtest.py | 1064 | 
1 files changed, 165 insertions, 899 deletions
| diff --git a/packages/Python/lldbsuite/test/lldbtest.py b/packages/Python/lldbsuite/test/lldbtest.py index de8f57f63706..ee876bd11169 100644 --- a/packages/Python/lldbsuite/test/lldbtest.py +++ b/packages/Python/lldbsuite/test/lldbtest.py @@ -31,39 +31,43 @@ OK  $   """ -from __future__ import print_function  from __future__ import absolute_import +from __future__ import print_function  # System modules  import abc  import collections -from distutils.version import LooseVersion +from functools import wraps  import gc  import glob  import inspect -import os, sys, traceback +import io  import os.path  import re  import signal  from subprocess import * +import sys  import time +import traceback  import types  # Third-party modules  import unittest2  from six import add_metaclass  from six import StringIO as SixStringIO -from six.moves.urllib import parse as urlparse  import six  # LLDB modules +import use_lldb_suite  import lldb  from . import configuration +from . import decorators +from . import lldbplatformutil  from . import lldbtest_config  from . import lldbutil  from . import test_categories - -from .result_formatter import EventBuilder +from lldbsuite.support import encoded_file +from lldbsuite.support import funcutils  # dosep.py starts lots and lots of dotest instances  # This option helps you find if two (or more) dotest instances are using the same @@ -186,10 +190,11 @@ def COMPLETION_MSG(str_before, str_after):      '''A generic message generator for the completion mechanism.'''      return "'%s' successfully completes to '%s'" % (str_before, str_after) -def EXP_MSG(str, exe): +def EXP_MSG(str, actual, exe):      '''A generic "'%s' returns expected result" message generator if exe.      Otherwise, it generates "'%s' matches expected result" message.''' -    return "'%s' %s expected result" % (str, 'returns' if exe else 'matches') +     +    return "'%s' %s expected result, got '%s'" % (str, 'returns' if exe else 'matches', actual.strip())  def SETTING_MSG(setting):      '''A generic "Value of setting '%s' is correct" message generator.''' @@ -201,7 +206,7 @@ def EnvArray():  def line_number(filename, string_to_match):      """Helper function to return the line number of the first matched string.""" -    with open(filename, 'r') as f: +    with io.open(filename, mode='r', encoding="utf-8") as f:          for i, line in enumerate(f):              if line.find(string_to_match) != -1:                  # Found our match. @@ -414,7 +419,14 @@ def system(commands, **kwargs):              cmd = kwargs.get("args")              if cmd is None:                  cmd = shellCommand -            raise CalledProcessError(retcode, cmd) +            cpe = CalledProcessError(retcode, cmd) +            # Ensure caller can access the stdout/stderr. +            cpe.lldb_extensions = { +                "stdout_content": this_output, +                "stderr_content": this_error, +                "command": shellCommand +            } +            raise cpe          output = output + this_output          error = error + this_error      return (output, error) @@ -435,804 +447,12 @@ def builder_module():          return __import__("builder_freebsd")      if sys.platform.startswith("netbsd"):          return __import__("builder_netbsd") +    if sys.platform.startswith("linux"): +        # sys.platform with Python-3.x returns 'linux', but with +        # Python-2.x it returns 'linux2'. +        return __import__("builder_linux")      return __import__("builder_" + sys.platform) -def run_adb_command(cmd, device_id): -    device_id_args = [] -    if device_id: -        device_id_args = ["-s", device_id] -    full_cmd = ["adb"] + device_id_args + cmd -    p = Popen(full_cmd, stdout=PIPE, stderr=PIPE) -    stdout, stderr = p.communicate() -    return p.returncode, stdout, stderr - -def append_android_envs(dictionary): -    if dictionary is None: -        dictionary = {} -    dictionary["OS"] = "Android" -    if android_device_api() >= 16: -        dictionary["PIE"] = 1 -    return dictionary - -def target_is_android(): -    if not hasattr(target_is_android, 'result'): -        triple = lldb.DBG.GetSelectedPlatform().GetTriple() -        match = re.match(".*-.*-.*-android", triple) -        target_is_android.result = match is not None -    return target_is_android.result - -def android_device_api(): -    if not hasattr(android_device_api, 'result'): -        assert configuration.lldb_platform_url is not None -        device_id = None -        parsed_url = urlparse.urlparse(configuration.lldb_platform_url) -        host_name = parsed_url.netloc.split(":")[0] -        if host_name != 'localhost': -            device_id = host_name -            if device_id.startswith('[') and device_id.endswith(']'): -                device_id = device_id[1:-1] -        retcode, stdout, stderr = run_adb_command( -            ["shell", "getprop", "ro.build.version.sdk"], device_id) -        if retcode == 0: -            android_device_api.result = int(stdout) -        else: -            raise LookupError( -                ">>> Unable to determine the API level of the Android device.\n" -                ">>> stdout:\n%s\n" -                ">>> stderr:\n%s\n" % (stdout, stderr)) -    return android_device_api.result - -def check_expected_version(comparison, expected, actual): -    def fn_leq(x,y): return x <= y -    def fn_less(x,y): return x < y -    def fn_geq(x,y): return x >= y -    def fn_greater(x,y): return x > y -    def fn_eq(x,y): return x == y -    def fn_neq(x,y): return x != y - -    op_lookup = { -        "==": fn_eq, -        "=": fn_eq, -        "!=": fn_neq, -        "<>": fn_neq, -        ">": fn_greater, -        "<": fn_less, -        ">=": fn_geq, -        "<=": fn_leq -        } -    expected_str = '.'.join([str(x) for x in expected]) -    actual_str = '.'.join([str(x) for x in actual]) - -    return op_lookup[comparison](LooseVersion(actual_str), LooseVersion(expected_str)) - -# -# Decorators for categorizing test cases. -# -from functools import wraps - -def add_test_categories(cat): -    """Add test categories to a TestCase method""" -    cat = test_categories.validate(cat, True) -    def impl(func): -        if isinstance(func, type) and issubclass(func, unittest2.TestCase): -            raise Exception("@add_test_categories can only be used to decorate a test method") -        if hasattr(func, "categories"): -            cat.extend(func.categories) -        func.categories = cat -        return func - -    return impl - -def benchmarks_test(func): -    """Decorate the item as a benchmarks test.""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@benchmarks_test can only be used to decorate a test method") -    @wraps(func) -    def wrapper(self, *args, **kwargs): -        self.skipTest("benchmarks test") -        return func(self, *args, **kwargs) - -    # Mark this function as such to separate them from the regular tests. -    wrapper.__benchmarks_test__ = True -    return wrapper - -def no_debug_info_test(func): -    """Decorate the item as a test what don't use any debug info. If this annotation is specified -       then the test runner won't generate a separate test for each debug info format. """ -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@no_debug_info_test can only be used to decorate a test method") -    @wraps(func) -    def wrapper(self, *args, **kwargs): -        return func(self, *args, **kwargs) - -    # Mark this function as such to separate them from the regular tests. -    wrapper.__no_debug_info_test__ = True -    return wrapper - -def debugserver_test(func): -    """Decorate the item as a debugserver test.""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@debugserver_test can only be used to decorate a test method") -    @wraps(func) -    def wrapper(self, *args, **kwargs): -        if configuration.dont_do_debugserver_test: -            self.skipTest("debugserver tests") -        return func(self, *args, **kwargs) - -    # Mark this function as such to separate them from the regular tests. -    wrapper.__debugserver_test__ = True -    return wrapper - -def llgs_test(func): -    """Decorate the item as a lldb-server test.""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@llgs_test can only be used to decorate a test method") -    @wraps(func) -    def wrapper(self, *args, **kwargs): -        if configuration.dont_do_llgs_test: -            self.skipTest("llgs tests") -        return func(self, *args, **kwargs) - -    # Mark this function as such to separate them from the regular tests. -    wrapper.__llgs_test__ = True -    return wrapper - -def not_remote_testsuite_ready(func): -    """Decorate the item as a test which is not ready yet for remote testsuite.""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@not_remote_testsuite_ready can only be used to decorate a test method") -    @wraps(func) -    def wrapper(self, *args, **kwargs): -        if lldb.remote_platform: -            self.skipTest("not ready for remote testsuite") -        return func(self, *args, **kwargs) - -    # Mark this function as such to separate them from the regular tests. -    wrapper.__not_ready_for_remote_testsuite_test__ = True -    return wrapper - -def expectedFailure(expected_fn, bugnumber=None): -    def expectedFailure_impl(func): -        @wraps(func) -        def wrapper(*args, **kwargs): -            from unittest2 import case -            self = args[0] -            if expected_fn(self): -                if configuration.results_formatter_object is not None: -                    # Mark this test as expected to fail. -                    configuration.results_formatter_object.handle_event( -                        EventBuilder.event_for_mark_test_expected_failure(self)) -                xfail_func = unittest2.expectedFailure(func) -                xfail_func(*args, **kwargs) -            else: -                func(*args, **kwargs) -        return wrapper -    # if bugnumber is not-callable(incluing None), that means decorator function is called with optional arguments -    # return decorator in this case, so it will be used to decorating original method -    if six.callable(bugnumber): -        return expectedFailure_impl(bugnumber) -    else: -        return expectedFailure_impl - -# You can also pass not_in(list) to reverse the sense of the test for the arguments that -# are simple lists, namely oslist, compiler, and debug_info. - -def not_in(iterable): -    return lambda x : x not in iterable - -def check_list_or_lambda(list_or_lambda, value): -    if six.callable(list_or_lambda): -        return list_or_lambda(value) -    elif isinstance(list_or_lambda, list): -        for item in list_or_lambda: -            if value in item: -                return True -        return False -    elif isinstance(list_or_lambda, str): -        return value is None or value in list_or_lambda -    else: -        return list_or_lambda is None or value is None or list_or_lambda == value - -def matchArchitectures(archs, actual_arch): -    retype = type(re.compile('hello, world')) -    list_passes = isinstance(archs, list) and actual_arch in archs -    basestring_passes = isinstance(archs, six.string_types) and actual_arch == archs -    regex_passes = isinstance(archs, retype) and re.match(archs, actual_arch) - -    return (list_passes or basestring_passes or regex_passes) - -# provide a function to xfail on defined oslist, compiler version, and archs -# if none is specified for any argument, that argument won't be checked and thus means for all -# for example, -# @expectedFailureAll, xfail for all platform/compiler/arch, -# @expectedFailureAll(compiler='gcc'), xfail for gcc on all platform/architecture -# @expectedFailureAll(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), xfail for gcc>=4.9 on linux with i386 -def expectedFailureAll(bugnumber=None, oslist=None, hostoslist=None, compiler=None, compiler_version=None, archs=None, triple=None, debug_info=None, swig_version=None, py_version=None): -    def fn(self): -        oslist_passes = check_list_or_lambda(oslist, self.getPlatform()) -        hostoslist_passes = check_list_or_lambda(hostoslist, getHostPlatform()) -        compiler_passes = check_list_or_lambda(self.getCompiler(), compiler) and self.expectedCompilerVersion(compiler_version) -        arch_passes = check_list_or_lambda(archs, self.getArchitecture()) -        triple_passes = triple is None or re.match(triple, lldb.DBG.GetSelectedPlatform().GetTriple()) -        debug_info_passes = check_list_or_lambda(debug_info, self.debug_info) -        swig_version_passes = (swig_version is None) or (not hasattr(lldb, 'swig_version')) or (check_expected_version(swig_version[0], swig_version[1], lldb.swig_version)) -        py_version_passes = (py_version is None) or check_expected_version(py_version[0], py_version[1], sys.version_info) - -        return (oslist_passes and -                hostoslist_passes and -                compiler_passes and -                arch_passes and -                triple_passes and -                debug_info_passes and -                swig_version_passes and -                py_version_passes) -    return expectedFailure(fn, bugnumber) - -def expectedFailureDwarf(bugnumber=None): -    return expectedFailureAll(bugnumber=bugnumber, debug_info="dwarf") - -def expectedFailureDwo(bugnumber=None): -    return expectedFailureAll(bugnumber=bugnumber, debug_info="dwo") - -def expectedFailureDsym(bugnumber=None): -    return expectedFailureAll(bugnumber=bugnumber, debug_info="dsym") - -def expectedFailureCompiler(compiler, compiler_version=None, bugnumber=None): -    if compiler_version is None: -        compiler_version=['=', None] -    return expectedFailureAll(bugnumber=bugnumber, compiler=compiler, compiler_version=compiler_version) - -# to XFAIL a specific clang versions, try this -# @expectedFailureClang('bugnumber', ['<=', '3.4']) -def expectedFailureClang(bugnumber=None, compiler_version=None): -    return expectedFailureCompiler('clang', compiler_version, bugnumber) - -def expectedFailureGcc(bugnumber=None, compiler_version=None): -    return expectedFailureCompiler('gcc', compiler_version, bugnumber) - -def expectedFailureIcc(bugnumber=None): -    return expectedFailureCompiler('icc', None, bugnumber) - -def expectedFailureArch(arch, bugnumber=None): -    def fn(self): -        return arch in self.getArchitecture() -    return expectedFailure(fn, bugnumber) - -def expectedFailurei386(bugnumber=None): -    return expectedFailureArch('i386', bugnumber) - -def expectedFailurex86_64(bugnumber=None): -    return expectedFailureArch('x86_64', bugnumber) - -def expectedFailureOS(oslist, bugnumber=None, compilers=None, debug_info=None, archs=None): -    def fn(self): -        return (self.getPlatform() in oslist and -                self.expectedCompiler(compilers) and -                (archs is None or self.getArchitecture() in archs) and -                (debug_info is None or self.debug_info in debug_info)) -    return expectedFailure(fn, bugnumber) - -def expectedFailureHostOS(oslist, bugnumber=None, compilers=None): -    def fn(self): -        return (getHostPlatform() in oslist and -                self.expectedCompiler(compilers)) -    return expectedFailure(fn, bugnumber) - -def expectedFailureDarwin(bugnumber=None, compilers=None, debug_info=None): -    # For legacy reasons, we support both "darwin" and "macosx" as OS X triples. -    return expectedFailureOS(getDarwinOSTriples(), bugnumber, compilers, debug_info=debug_info) - -def expectedFailureFreeBSD(bugnumber=None, compilers=None, debug_info=None): -    return expectedFailureOS(['freebsd'], bugnumber, compilers, debug_info=debug_info) - -def expectedFailureLinux(bugnumber=None, compilers=None, debug_info=None, archs=None): -    return expectedFailureOS(['linux'], bugnumber, compilers, debug_info=debug_info, archs=archs) - -def expectedFailureNetBSD(bugnumber=None, compilers=None, debug_info=None): -    return expectedFailureOS(['netbsd'], bugnumber, compilers, debug_info=debug_info) - -def expectedFailureWindows(bugnumber=None, compilers=None, debug_info=None): -    return expectedFailureOS(['windows'], bugnumber, compilers, debug_info=debug_info) - -def expectedFailureHostWindows(bugnumber=None, compilers=None): -    return expectedFailureHostOS(['windows'], bugnumber, compilers) - -def matchAndroid(api_levels=None, archs=None): -    def match(self): -        if not target_is_android(): -            return False -        if archs is not None and self.getArchitecture() not in archs: -            return False -        if api_levels is not None and android_device_api() not in api_levels: -            return False -        return True -    return match - - -def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None): -    """ Mark a test as xfail for Android. - -    Arguments: -        bugnumber - The LLVM pr associated with the problem. -        api_levels - A sequence of numbers specifying the Android API levels -            for which a test is expected to fail. None means all API level. -        arch - A sequence of architecture names specifying the architectures -            for which a test is expected to fail. None means all architectures. -    """ -    return expectedFailure(matchAndroid(api_levels, archs), bugnumber) - -# Flakey tests get two chances to run. If they fail the first time round, the result formatter -# makes sure it is run one more time. -def expectedFlakey(expected_fn, bugnumber=None): -    def expectedFailure_impl(func): -        @wraps(func) -        def wrapper(*args, **kwargs): -            self = args[0] -            if expected_fn(self): -                # Send event marking test as explicitly eligible for rerunning. -                if configuration.results_formatter_object is not None: -                    # Mark this test as rerunnable. -                    configuration.results_formatter_object.handle_event( -                        EventBuilder.event_for_mark_test_rerun_eligible(self)) -            func(*args, **kwargs) -        return wrapper -    # if bugnumber is not-callable(incluing None), that means decorator function is called with optional arguments -    # return decorator in this case, so it will be used to decorating original method -    if six.callable(bugnumber): -        return expectedFailure_impl(bugnumber) -    else: -        return expectedFailure_impl - -def expectedFlakeyDwarf(bugnumber=None): -    def fn(self): -        return self.debug_info == "dwarf" -    return expectedFlakey(fn, bugnumber) - -def expectedFlakeyDsym(bugnumber=None): -    def fn(self): -        return self.debug_info == "dwarf" -    return expectedFlakey(fn, bugnumber) - -def expectedFlakeyOS(oslist, bugnumber=None, compilers=None): -    def fn(self): -        return (self.getPlatform() in oslist and -                self.expectedCompiler(compilers)) -    return expectedFlakey(fn, bugnumber) - -def expectedFlakeyDarwin(bugnumber=None, compilers=None): -    # For legacy reasons, we support both "darwin" and "macosx" as OS X triples. -    return expectedFlakeyOS(getDarwinOSTriples(), bugnumber, compilers) - -def expectedFlakeyFreeBSD(bugnumber=None, compilers=None): -    return expectedFlakeyOS(['freebsd'], bugnumber, compilers) - -def expectedFlakeyLinux(bugnumber=None, compilers=None): -    return expectedFlakeyOS(['linux'], bugnumber, compilers) - -def expectedFlakeyNetBSD(bugnumber=None, compilers=None): -    return expectedFlakeyOS(['netbsd'], bugnumber, compilers) - -def expectedFlakeyCompiler(compiler, compiler_version=None, bugnumber=None): -    if compiler_version is None: -        compiler_version=['=', None] -    def fn(self): -        return compiler in self.getCompiler() and self.expectedCompilerVersion(compiler_version) -    return expectedFlakey(fn, bugnumber) - -# @expectedFlakeyClang('bugnumber', ['<=', '3.4']) -def expectedFlakeyClang(bugnumber=None, compiler_version=None): -    return expectedFlakeyCompiler('clang', compiler_version, bugnumber) - -# @expectedFlakeyGcc('bugnumber', ['<=', '3.4']) -def expectedFlakeyGcc(bugnumber=None, compiler_version=None): -    return expectedFlakeyCompiler('gcc', compiler_version, bugnumber) - -def expectedFlakeyAndroid(bugnumber=None, api_levels=None, archs=None): -    return expectedFlakey(matchAndroid(api_levels, archs), bugnumber) - -def skipIfRemote(func): -    """Decorate the item to skip tests if testing remotely.""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@skipIfRemote can only be used to decorate a test method") -    @wraps(func) -    def wrapper(*args, **kwargs): -        from unittest2 import case -        if lldb.remote_platform: -            self = args[0] -            self.skipTest("skip on remote platform") -        else: -            func(*args, **kwargs) -    return wrapper - -def skipUnlessListedRemote(remote_list=None): -    def myImpl(func): -        if isinstance(func, type) and issubclass(func, unittest2.TestCase): -            raise Exception("@skipIfRemote can only be used to decorate a " -                            "test method") - -        @wraps(func) -        def wrapper(*args, **kwargs): -            if remote_list and lldb.remote_platform: -                self = args[0] -                triple = self.dbg.GetSelectedPlatform().GetTriple() -                for r in remote_list: -                    if r in triple: -                        func(*args, **kwargs) -                        return -                self.skipTest("skip on remote platform %s" % str(triple)) -            else: -                func(*args, **kwargs) -        return wrapper - -    return myImpl - -def skipIfRemoteDueToDeadlock(func): -    """Decorate the item to skip tests if testing remotely due to the test deadlocking.""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@skipIfRemote can only be used to decorate a test method") -    @wraps(func) -    def wrapper(*args, **kwargs): -        from unittest2 import case -        if lldb.remote_platform: -            self = args[0] -            self.skipTest("skip on remote platform (deadlocks)") -        else: -            func(*args, **kwargs) -    return wrapper - -def skipIfNoSBHeaders(func): -    """Decorate the item to mark tests that should be skipped when LLDB is built with no SB API headers.""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@skipIfNoSBHeaders can only be used to decorate a test method") -    @wraps(func) -    def wrapper(*args, **kwargs): -        from unittest2 import case -        self = args[0] -        if sys.platform.startswith("darwin"): -            header = os.path.join(os.environ["LLDB_LIB_DIR"], 'LLDB.framework', 'Versions','Current','Headers','LLDB.h') -        else: -            header = os.path.join(os.environ["LLDB_SRC"], "include", "lldb", "API", "LLDB.h") -        platform = sys.platform -        if not os.path.exists(header): -            self.skipTest("skip because LLDB.h header not found") -        else: -            func(*args, **kwargs) -    return wrapper - -def skipIfiOSSimulator(func): -    """Decorate the item to skip tests that should be skipped on the iOS Simulator.""" -    return unittest2.skipIf(configuration.lldb_platform_name == 'ios-simulator', 'skip on the iOS Simulator')(func) - -def skipIfFreeBSD(func): -    """Decorate the item to skip tests that should be skipped on FreeBSD.""" -    return skipIfPlatform(["freebsd"])(func) - -def skipIfNetBSD(func): -    """Decorate the item to skip tests that should be skipped on NetBSD.""" -    return skipIfPlatform(["netbsd"])(func) - -def getDarwinOSTriples(): -    return ['darwin', 'macosx', 'ios'] - -def skipIfDarwin(func): -    """Decorate the item to skip tests that should be skipped on Darwin.""" -    return skipIfPlatform(getDarwinOSTriples())(func) - -def skipIfLinux(func): -    """Decorate the item to skip tests that should be skipped on Linux.""" -    return skipIfPlatform(["linux"])(func) - -def skipUnlessHostLinux(func): -    """Decorate the item to skip tests that should be skipped on any non Linux host.""" -    return skipUnlessHostPlatform(["linux"])(func) - -def skipIfWindows(func): -    """Decorate the item to skip tests that should be skipped on Windows.""" -    return skipIfPlatform(["windows"])(func) - -def skipIfHostWindows(func): -    """Decorate the item to skip tests that should be skipped on Windows.""" -    return skipIfHostPlatform(["windows"])(func) - -def skipUnlessWindows(func): -    """Decorate the item to skip tests that should be skipped on any non-Windows platform.""" -    return skipUnlessPlatform(["windows"])(func) - -def skipUnlessDarwin(func): -    """Decorate the item to skip tests that should be skipped on any non Darwin platform.""" -    return skipUnlessPlatform(getDarwinOSTriples())(func) - -def skipUnlessGoInstalled(func): -    """Decorate the item to skip tests when no Go compiler is available.""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@skipIfGcc can only be used to decorate a test method") -    @wraps(func) -    def wrapper(*args, **kwargs): -        from unittest2 import case -        self = args[0] -        compiler = self.getGoCompilerVersion() -        if not compiler: -            self.skipTest("skipping because go compiler not found") -        else: -            # Ensure the version is the minimum version supported by -            # the LLDB go support. -            match_version = re.search(r"(\d+\.\d+(\.\d+)?)", compiler) -            if not match_version: -                # Couldn't determine version. -                self.skipTest( -                    "skipping because go version could not be parsed " -                    "out of {}".format(compiler)) -            else: -                from distutils.version import StrictVersion -                min_strict_version = StrictVersion("1.4.0") -                compiler_strict_version = StrictVersion(match_version.group(1)) -                if compiler_strict_version < min_strict_version: -                    self.skipTest( -                        "skipping because available go version ({}) does " -                        "not meet minimum required go version ({})".format( -                            compiler_strict_version, -                            min_strict_version)) -            func(*args, **kwargs) -    return wrapper - -def getPlatform(): -    """Returns the target platform which the tests are running on.""" -    platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2] -    if platform.startswith('freebsd'): -        platform = 'freebsd' -    elif platform.startswith('netbsd'): -        platform = 'netbsd' -    return platform - -def getHostPlatform(): -    """Returns the host platform running the test suite.""" -    # Attempts to return a platform name matching a target Triple platform. -    if sys.platform.startswith('linux'): -        return 'linux' -    elif sys.platform.startswith('win32'): -        return 'windows' -    elif sys.platform.startswith('darwin'): -        return 'darwin' -    elif sys.platform.startswith('freebsd'): -        return 'freebsd' -    elif sys.platform.startswith('netbsd'): -        return 'netbsd' -    else: -        return sys.platform - -def platformIsDarwin(): -    """Returns true if the OS triple for the selected platform is any valid apple OS""" -    return getPlatform() in getDarwinOSTriples() - -def skipIfHostIncompatibleWithRemote(func): -    """Decorate the item to skip tests if binaries built on this host are incompatible.""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@skipIfHostIncompatibleWithRemote can only be used to decorate a test method") -    @wraps(func) -    def wrapper(*args, **kwargs): -        from unittest2 import case -        self = args[0] -        host_arch = self.getLldbArchitecture() -        host_platform = getHostPlatform() -        target_arch = self.getArchitecture() -        target_platform = 'darwin' if self.platformIsDarwin() else self.getPlatform() -        if not (target_arch == 'x86_64' and host_arch == 'i386') and host_arch != target_arch: -            self.skipTest("skipping because target %s is not compatible with host architecture %s" % (target_arch, host_arch)) -        elif target_platform != host_platform: -            self.skipTest("skipping because target is %s but host is %s" % (target_platform, host_platform)) -        else: -            func(*args, **kwargs) -    return wrapper - -def skipIfHostPlatform(oslist): -    """Decorate the item to skip tests if running on one of the listed host platforms.""" -    return unittest2.skipIf(getHostPlatform() in oslist, -                            "skip on %s" % (", ".join(oslist))) - -def skipUnlessHostPlatform(oslist): -    """Decorate the item to skip tests unless running on one of the listed host platforms.""" -    return unittest2.skipUnless(getHostPlatform() in oslist, -                                "requires on of %s" % (", ".join(oslist))) - -def skipUnlessArch(archs): -    """Decorate the item to skip tests unless running on one of the listed architectures.""" -    def myImpl(func): -        if isinstance(func, type) and issubclass(func, unittest2.TestCase): -            raise Exception("@skipUnlessArch can only be used to decorate a test method") - -        @wraps(func) -        def wrapper(*args, **kwargs): -            self = args[0] -            if not matchArchitectures(archs, self.getArchitecture()): -                self.skipTest("skipping for architecture %s" % (self.getArchitecture()))  -            else: -                func(*args, **kwargs) -        return wrapper - -    return myImpl - -def skipIfPlatform(oslist): -    """Decorate the item to skip tests if running on one of the listed platforms.""" -    return unittest2.skipIf(getPlatform() in oslist, -                            "skip on %s" % (", ".join(oslist))) - -def skipUnlessPlatform(oslist): -    """Decorate the item to skip tests unless running on one of the listed platforms.""" -    return unittest2.skipUnless(getPlatform() in oslist, -                                "requires on of %s" % (", ".join(oslist))) - -def skipIfLinuxClang(func): -    """Decorate the item to skip tests that should be skipped if building on  -       Linux with clang. -    """ -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@skipIfLinuxClang can only be used to decorate a test method") -    @wraps(func) -    def wrapper(*args, **kwargs): -        from unittest2 import case -        self = args[0] -        compiler = self.getCompiler() -        platform = self.getPlatform() -        if "clang" in compiler and platform == "linux": -            self.skipTest("skipping because Clang is used on Linux") -        else: -            func(*args, **kwargs) -    return wrapper - -# provide a function to skip on defined oslist, compiler version, and archs -# if none is specified for any argument, that argument won't be checked and thus means for all -# for example, -# @skipIf, skip for all platform/compiler/arch, -# @skipIf(compiler='gcc'), skip for gcc on all platform/architecture -# @skipIf(bugnumber, ["linux"], "gcc", ['>=', '4.9'], ['i386']), skip for gcc>=4.9 on linux with i386 - -# TODO: refactor current code, to make skipIfxxx functions to call this function -def skipIf(bugnumber=None, oslist=None, compiler=None, compiler_version=None, archs=None, debug_info=None, swig_version=None, py_version=None, remote=None): -    def fn(self): -        oslist_passes = check_list_or_lambda(oslist, self.getPlatform()) -        compiler_passes = check_list_or_lambda(self.getCompiler(), compiler) and self.expectedCompilerVersion(compiler_version) -        arch_passes = check_list_or_lambda(archs, self.getArchitecture()) -        debug_info_passes = check_list_or_lambda(debug_info, self.debug_info) -        swig_version_passes = (swig_version is None) or (not hasattr(lldb, 'swig_version')) or (check_expected_version(swig_version[0], swig_version[1], lldb.swig_version)) -        py_version_passes = (py_version is None) or check_expected_version(py_version[0], py_version[1], sys.version_info) -        remote_passes = (remote is None) or (remote == (lldb.remote_platform is not None)) - -        return (oslist_passes and -                compiler_passes and -                arch_passes and -                debug_info_passes and -                swig_version_passes and -                py_version_passes and -                remote_passes) - -    local_vars = locals() -    args = [x for x in inspect.getargspec(skipIf).args] -    arg_vals = [eval(x, globals(), local_vars) for x in args] -    args = [x for x in zip(args, arg_vals) if x[1] is not None] -    reasons = ['%s=%s' % (x, str(y)) for (x,y) in args] -    return skipTestIfFn(fn, bugnumber, skipReason='skipping because ' + ' && '.join(reasons)) - -def skipIfDebugInfo(bugnumber=None, debug_info=None): -    return skipIf(bugnumber=bugnumber, debug_info=debug_info) - -def skipIfDWO(bugnumber=None): -    return skipIfDebugInfo(bugnumber, ["dwo"]) - -def skipIfDwarf(bugnumber=None): -    return skipIfDebugInfo(bugnumber, ["dwarf"]) - -def skipIfDsym(bugnumber=None): -    return skipIfDebugInfo(bugnumber, ["dsym"]) - -def skipTestIfFn(expected_fn, bugnumber=None, skipReason=None): -    def skipTestIfFn_impl(func): -        @wraps(func) -        def wrapper(*args, **kwargs): -            from unittest2 import case -            self = args[0] -            if expected_fn(self): -               self.skipTest(skipReason) -            else: -                func(*args, **kwargs) -        return wrapper -    if six.callable(bugnumber): -        return skipTestIfFn_impl(bugnumber) -    else: -        return skipTestIfFn_impl - -def skipIfGcc(func): -    """Decorate the item to skip tests that should be skipped if building with gcc .""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@skipIfGcc can only be used to decorate a test method") -    @wraps(func) -    def wrapper(*args, **kwargs): -        from unittest2 import case -        self = args[0] -        compiler = self.getCompiler() -        if "gcc" in compiler: -            self.skipTest("skipping because gcc is the test compiler") -        else: -            func(*args, **kwargs) -    return wrapper - -def skipIfIcc(func): -    """Decorate the item to skip tests that should be skipped if building with icc .""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@skipIfIcc can only be used to decorate a test method") -    @wraps(func) -    def wrapper(*args, **kwargs): -        from unittest2 import case -        self = args[0] -        compiler = self.getCompiler() -        if "icc" in compiler: -            self.skipTest("skipping because icc is the test compiler") -        else: -            func(*args, **kwargs) -    return wrapper - -def skipIfi386(func): -    """Decorate the item to skip tests that should be skipped if building 32-bit.""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@skipIfi386 can only be used to decorate a test method") -    @wraps(func) -    def wrapper(*args, **kwargs): -        from unittest2 import case -        self = args[0] -        if "i386" == self.getArchitecture(): -            self.skipTest("skipping because i386 is not a supported architecture") -        else: -            func(*args, **kwargs) -    return wrapper - -def skipIfTargetAndroid(api_levels=None, archs=None): -    """Decorator to skip tests when the target is Android. - -    Arguments: -        api_levels - The API levels for which the test should be skipped. If -            it is None, then the test will be skipped for all API levels. -        arch - A sequence of architecture names specifying the architectures -            for which a test is skipped. None means all architectures. -    """ -    def myImpl(func): -        if isinstance(func, type) and issubclass(func, unittest2.TestCase): -            raise Exception("@skipIfTargetAndroid can only be used to " -                            "decorate a test method") -        @wraps(func) -        def wrapper(*args, **kwargs): -            from unittest2 import case -            self = args[0] -            if matchAndroid(api_levels, archs)(self): -                self.skipTest("skiped on Android target with API %d and architecture %s" % -                        (android_device_api(), self.getArchitecture())) -            func(*args, **kwargs) -        return wrapper -    return myImpl - -def skipUnlessCompilerRt(func): -    """Decorate the item to skip tests if testing remotely.""" -    if isinstance(func, type) and issubclass(func, unittest2.TestCase): -        raise Exception("@skipUnless can only be used to decorate a test method") -    @wraps(func) -    def wrapper(*args, **kwargs): -        from unittest2 import case -        import os.path -        compilerRtPath = os.path.join(os.path.dirname(__file__), "..", "..", "..", "..", "llvm","projects","compiler-rt") -        print(compilerRtPath) -        if not os.path.exists(compilerRtPath): -            self = args[0] -            self.skipTest("skip if compiler-rt not found") -        else: -            func(*args, **kwargs) -    return wrapper - -class _PlatformContext(object): -    """Value object class which contains platform-specific options.""" - -    def __init__(self, shlib_environment_var, shlib_prefix, shlib_extension): -        self.shlib_environment_var = shlib_environment_var -        self.shlib_prefix = shlib_prefix -        self.shlib_extension = shlib_extension -  class Base(unittest2.TestCase):      """ @@ -1298,12 +518,7 @@ class Base(unittest2.TestCase):                  raise ioerror          # Set platform context. -        if platformIsDarwin(): -            cls.platformContext = _PlatformContext('DYLD_LIBRARY_PATH', 'lib', 'dylib') -        elif getPlatform() in ("freebsd", "linux", "netbsd"): -            cls.platformContext = _PlatformContext('LD_LIBRARY_PATH', 'lib', 'so') -        else: -            cls.platformContext = None +        cls.platformContext = lldbplatformutil.createPlatformContext()      @classmethod      def tearDownClass(cls): @@ -1368,7 +583,7 @@ class Base(unittest2.TestCase):              else:                  categories = "default" -            if channel == "gdb-remote": +            if channel == "gdb-remote" and lldb.remote_platform is None:                  # communicate gdb-remote categories to debugserver                  os.environ["LLDB_DEBUGSERVER_LOG_FLAGS"] = categories @@ -1377,15 +592,17 @@ class Base(unittest2.TestCase):                  raise Exception('log enable failed (check LLDB_LOG_OPTION env variable)')          # Communicate log path name to debugserver & lldb-server -        server_log_path = "{}-server.log".format(log_basename) -        open(server_log_path, 'w').close() -        os.environ["LLDB_DEBUGSERVER_LOG_FILE"] = server_log_path +        # For remote debugging, these variables need to be set when starting the platform +        # instance. +        if lldb.remote_platform is None: +            server_log_path = "{}-server.log".format(log_basename) +            open(server_log_path, 'w').close() +            os.environ["LLDB_DEBUGSERVER_LOG_FILE"] = server_log_path -        # Communicate channels to lldb-server -        os.environ["LLDB_SERVER_LOG_CHANNELS"] = ":".join(lldbtest_config.channels) +            # Communicate channels to lldb-server +            os.environ["LLDB_SERVER_LOG_CHANNELS"] = ":".join(lldbtest_config.channels) -        if len(lldbtest_config.channels) == 0: -            return +        self.addTearDownHook(self.disableLogChannelsForCurrentTest)      def disableLogChannelsForCurrentTest(self):          # close all log files that we opened @@ -1396,6 +613,42 @@ class Base(unittest2.TestCase):              if not self.res.Succeeded():                  raise Exception('log disable failed (check LLDB_LOG_OPTION env variable)') +        # Retrieve the server log (if any) from the remote system. It is assumed the server log +        # is writing to the "server.log" file in the current test directory. This can be +        # achieved by setting LLDB_DEBUGSERVER_LOG_FILE="server.log" when starting remote +        # platform. If the remote logging is not enabled, then just let the Get() command silently +        # fail. +        if lldb.remote_platform: +            lldb.remote_platform.Get(lldb.SBFileSpec("server.log"), +                    lldb.SBFileSpec(self.getLogBasenameForCurrentTest()+"-server.log")) + +    def setPlatformWorkingDir(self): +        if not lldb.remote_platform or not configuration.lldb_platform_working_dir: +            return + +        remote_test_dir = lldbutil.join_remote_paths( +                configuration.lldb_platform_working_dir, +                self.getArchitecture(), +                str(self.test_number), +                self.mydir) +        error = lldb.remote_platform.MakeDirectory(remote_test_dir, 448) # 448 = 0o700 +        if error.Success(): +            lldb.remote_platform.SetWorkingDirectory(remote_test_dir) + +            # This function removes all files from the current working directory while leaving +            # the directories in place. The cleaup is required to reduce the disk space required +            # by the test suit while leaving the directories untached is neccessary because +            # sub-directories might belong to an other test +            def clean_working_directory(): +                # TODO: Make it working on Windows when we need it for remote debugging support +                # TODO: Replace the heuristic to remove the files with a logic what collects the +                # list of files we have to remove during test runs. +                shell_cmd = lldb.SBPlatformShellCommand("rm %s/*" % remote_test_dir) +                lldb.remote_platform.Run(shell_cmd) +            self.addTearDownHook(clean_working_directory) +        else: +            print("error: making remote directory '%s': %s" % (remote_test_dir, error)) +      def setUp(self):          """Fixture for unittest test case setup. @@ -1458,7 +711,7 @@ class Base(unittest2.TestCase):          session_file = "{}.log".format(self.log_basename)          # Python 3 doesn't support unbuffered I/O in text mode.  Open buffered. -        self.session = open(session_file, "w") +        self.session = encoded_file.open(session_file, "utf-8", mode="w")          # Optimistically set __errored__, __failed__, __expected__ to False          # initially.  If the test errored/failed, the session info @@ -1501,6 +754,7 @@ class Base(unittest2.TestCase):          # And the result object.          self.res = lldb.SBCommandReturnObject() +        self.setPlatformWorkingDir()          self.enableLogChannelsForCurrentTest()          #Initialize debug_info @@ -1652,11 +906,7 @@ class Base(unittest2.TestCase):          for hook in reversed(self.hooks):              with recording(self, traceAlways) as sbuf:                  print("Executing tearDown hook:", getsource_if_available(hook), file=sbuf) -            import inspect -            hook_argc = len(inspect.getargspec(hook).args) -            if hook_argc == 0 or getattr(hook,'im_self',None): -                hook() -            elif hook_argc == 1: +            if funcutils.requires_self(hook):                  hook(self)              else:                  hook() # try the plain call and hope it works @@ -1673,8 +923,6 @@ class Base(unittest2.TestCase):                  for dict in reversed(self.dicts):                      self.cleanup(dictionary=dict) -        self.disableLogChannelsForCurrentTest() -      # =========================================================      # Various callbacks to allow introspection of test progress      # ========================================================= @@ -1751,19 +999,27 @@ class Base(unittest2.TestCase):          if not os.path.isdir(dname):              os.mkdir(dname) -        compiler = self.getCompiler() - -        if compiler[1] == ':': -            compiler = compiler[2:] -        if os.path.altsep is not None: -            compiler = compiler.replace(os.path.altsep, os.path.sep) - -        fname = "{}-{}-{}".format(self.id(), self.getArchitecture(), "_".join(compiler.split(os.path.sep))) -        if len(fname) > 200: -            fname = "{}-{}-{}".format(self.id(), self.getArchitecture(), compiler.split(os.path.sep)[-1]) - +        components = []          if prefix is not None: -            fname = "{}-{}".format(prefix, fname) +            components.append(prefix) +        for c in configuration.session_file_format: +            if c == 'f': +                components.append(self.__class__.__module__) +            elif c == 'n': +                components.append(self.__class__.__name__) +            elif c == 'c': +                compiler = self.getCompiler() + +                if compiler[1] == ':': +                    compiler = compiler[2:] +                if os.path.altsep is not None: +                    compiler = compiler.replace(os.path.altsep, os.path.sep) +                components.extend([x for x in compiler.split(os.path.sep) if x != ""]) +            elif c == 'a': +                components.append(self.getArchitecture()) +            elif c == 'm': +                components.append(self.testMethodName) +        fname = "-".join(components)          return os.path.join(dname, fname) @@ -1844,23 +1100,13 @@ class Base(unittest2.TestCase):                          # it silently replaces the destination.  Ultimately this means that atomic renames are not                          # guaranteed to be possible on Windows, but we need this to work anyway, so just remove the                          # destination first if it already exists. -                        os.remove(dst) +                        remove_file(dst)                      os.rename(src, dst)          else:              # success!  (and we don't want log files) delete log files              for log_file in log_files_for_this_test: -                try: -                    os.unlink(log_file) -                except: -                    # We've seen consistent unlink failures on Windows, perhaps because the -                    # just-created log file is being scanned by anti-virus.  Empirically, this -                    # sleep-and-retry approach allows tests to succeed much more reliably. -                    # Attempts to figure out exactly what process was still holding a file handle -                    # have failed because running instrumentation like Process Monitor seems to -                    # slow things down enough that the problem becomes much less consistent. -                    time.sleep(0.5) -                    os.unlink(log_file) +                remove_file(log_file)      # ====================================================      # Config. methods supported through a plugin interface @@ -1912,11 +1158,10 @@ class Base(unittest2.TestCase):          """ Returns a string that represents the compiler version.              Supports: llvm, clang.          """ -        from .lldbutil import which          version = 'unknown'          compiler = self.getCompilerBinary() -        version_output = system([[which(compiler), "-v"]])[1] +        version_output = system([[compiler, "-v"]])[1]          for line in version_output.split(os.linesep):              m = re.search('version ([0-9\.]+)', line)              if m: @@ -1937,11 +1182,11 @@ class Base(unittest2.TestCase):      def platformIsDarwin(self):          """Returns true if the OS triple for the selected platform is any valid apple OS""" -        return platformIsDarwin() +        return lldbplatformutil.platformIsDarwin()      def getPlatform(self):          """Returns the target platform the test suite is running on.""" -        return getPlatform() +        return lldbplatformutil.getPlatform()      def isIntelCompiler(self):          """ Returns true if using an Intel (ICC) compiler, false otherwise. """ @@ -2097,8 +1342,7 @@ class Base(unittest2.TestCase):      def buildDefault(self, architecture=None, compiler=None, dictionary=None, clean=True):          """Platform specific way to build the default binaries."""          module = builder_module() -        if target_is_android(): -            dictionary = append_android_envs(dictionary) +        dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)          if not module.buildDefault(self, architecture, compiler, dictionary, clean):              raise Exception("Don't know how to build default binary") @@ -2111,19 +1355,23 @@ class Base(unittest2.TestCase):      def buildDwarf(self, architecture=None, compiler=None, dictionary=None, clean=True):          """Platform specific way to build binaries with dwarf maps."""          module = builder_module() -        if target_is_android(): -            dictionary = append_android_envs(dictionary) +        dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)          if not module.buildDwarf(self, architecture, compiler, dictionary, clean):              raise Exception("Don't know how to build binary with dwarf")      def buildDwo(self, architecture=None, compiler=None, dictionary=None, clean=True):          """Platform specific way to build binaries with dwarf maps."""          module = builder_module() -        if target_is_android(): -            dictionary = append_android_envs(dictionary) +        dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)          if not module.buildDwo(self, architecture, compiler, dictionary, clean):              raise Exception("Don't know how to build binary with dwo") +    def buildGModules(self, architecture=None, compiler=None, dictionary=None, clean=True): +        """Platform specific way to build binaries with gmodules info.""" +        module = builder_module() +        if not module.buildGModules(self, architecture, compiler, dictionary, clean): +            raise Exception("Don't know how to build binary with gmodules") +      def buildGo(self):          """Build the default go binary.          """ @@ -2221,9 +1469,15 @@ class Base(unittest2.TestCase):  # Metaclass for TestBase to change the list of test metods when a new TestCase is loaded.  # We change the test methods to create a new test method for each test for each debug info we are  # testing. The name of the new test method will be '<original-name>_<debug-info>' and with adding -# the new test method we remove the old method at the same time. +# the new test method we remove the old method at the same time. This functionality can be +# supressed by at test case level setting the class attribute NO_DEBUG_INFO_TESTCASE or at test +# level by using the decorator @no_debug_info_test.  class LLDBTestCaseFactory(type):      def __new__(cls, name, bases, attrs): +        original_testcase = super(LLDBTestCaseFactory, cls).__new__(cls, name, bases, attrs) +        if original_testcase.NO_DEBUG_INFO_TESTCASE: +            return original_testcase +          newattrs = {}          for attrname, attrvalue in attrs.items():              if attrname.startswith("test") and not getattr(attrvalue, "__no_debug_info_test__", False): @@ -2236,10 +1490,11 @@ class LLDBTestCaseFactory(type):                  if not categories:                      categories = all_dbginfo_categories -                supported_categories = [x for x in categories  -                                        if test_categories.is_supported_on_platform(x, target_platform)] +                supported_categories = [x for x in categories +                                        if test_categories.is_supported_on_platform( +                                            x, target_platform, configuration.compilers)]                  if "dsym" in supported_categories: -                    @add_test_categories(["dsym"]) +                    @decorators.add_test_categories(["dsym"])                      @wraps(attrvalue)                      def dsym_test_method(self, attrvalue=attrvalue):                          self.debug_info = "dsym" @@ -2249,7 +1504,7 @@ class LLDBTestCaseFactory(type):                      newattrs[dsym_method_name] = dsym_test_method                  if "dwarf" in supported_categories: -                    @add_test_categories(["dwarf"]) +                    @decorators.add_test_categories(["dwarf"])                      @wraps(attrvalue)                      def dwarf_test_method(self, attrvalue=attrvalue):                          self.debug_info = "dwarf" @@ -2259,7 +1514,7 @@ class LLDBTestCaseFactory(type):                      newattrs[dwarf_method_name] = dwarf_test_method                  if "dwo" in supported_categories: -                    @add_test_categories(["dwo"]) +                    @decorators.add_test_categories(["dwo"])                      @wraps(attrvalue)                      def dwo_test_method(self, attrvalue=attrvalue):                          self.debug_info = "dwo" @@ -2267,6 +1522,17 @@ class LLDBTestCaseFactory(type):                      dwo_method_name = attrname + "_dwo"                      dwo_test_method.__name__ = dwo_method_name                      newattrs[dwo_method_name] = dwo_test_method + +                if "gmodules" in supported_categories: +                    @decorators.add_test_categories(["gmodules"]) +                    @wraps(attrvalue) +                    def gmodules_test_method(self, attrvalue=attrvalue): +                        self.debug_info = "gmodules" +                        return attrvalue(self) +                    gmodules_method_name = attrname + "_gmodules" +                    gmodules_test_method.__name__ = gmodules_method_name +                    newattrs[gmodules_method_name] = gmodules_test_method +              else:                  newattrs[attrname] = attrvalue          return super(LLDBTestCaseFactory, cls).__new__(cls, name, bases, newattrs) @@ -2325,6 +1591,10 @@ class TestBase(Base):            Mac OS X implementation is located in plugins/darwin.py.      """ +    # Subclasses can set this to true (if they don't depend on debug info) to avoid running the +    # test multiple times with various debug info types. +    NO_DEBUG_INFO_TESTCASE = False +      # Maximum allowed attempts when launching the inferior process.      # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable.      maxLaunchCount = 3; @@ -2381,30 +1651,6 @@ class TestBase(Base):          # And the result object.          self.res = lldb.SBCommandReturnObject() -        if lldb.remote_platform and configuration.lldb_platform_working_dir: -            remote_test_dir = lldbutil.join_remote_paths( -                    configuration.lldb_platform_working_dir, -                    self.getArchitecture(), -                    str(self.test_number), -                    self.mydir) -            error = lldb.remote_platform.MakeDirectory(remote_test_dir, 448) # 448 = 0o700 -            if error.Success(): -                lldb.remote_platform.SetWorkingDirectory(remote_test_dir) - -                # This function removes all files from the current working directory while leaving -                # the directories in place. The cleaup is required to reduce the disk space required -                # by the test suit while leaving the directories untached is neccessary because -                # sub-directories might belong to an other test -                def clean_working_directory(): -                    # TODO: Make it working on Windows when we need it for remote debugging support -                    # TODO: Replace the heuristic to remove the files with a logic what collects the -                    # list of files we have to remove during test runs. -                    shell_cmd = lldb.SBPlatformShellCommand("rm %s/*" % remote_test_dir) -                    lldb.remote_platform.Run(shell_cmd) -                self.addTearDownHook(clean_working_directory) -            else: -                print("error: making remote directory '%s': %s" % (remote_test_dir, error)) -          def registerSharedLibrariesWithTarget(self, target, shlibs):          '''If we are remotely running the test suite, register the shared libraries with the target so they get uploaded, otherwise do nothing @@ -2608,7 +1854,7 @@ class TestBase(Base):                  break          self.assertTrue(matched if matching else not matched, -                        msg if msg else EXP_MSG(str, exe)) +                        msg if msg else EXP_MSG(str, output, exe))          return match_object         @@ -2682,10 +1928,10 @@ class TestBase(Base):          # Look for sub strings, if specified.          keepgoing = matched if matching else not matched          if substrs and keepgoing: -            for str in substrs: -                matched = output.find(str) != -1 +            for substr in substrs: +                matched = output.find(substr) != -1                  with recording(self, trace) as sbuf: -                    print("%s sub string: %s" % (heading, str), file=sbuf) +                    print("%s sub string: %s" % (heading, substr), file=sbuf)                      print("Matched" if matched else "Not matched", file=sbuf)                  keepgoing = matched if matching else not matched                  if not keepgoing: @@ -2705,7 +1951,7 @@ class TestBase(Base):                      break          self.assertTrue(matched if matching else not matched, -                        msg if msg else EXP_MSG(str, exe)) +                        msg if msg else EXP_MSG(str, output, exe))      def invoke(self, obj, name, trace=False):          """Use reflection to call a method dynamically with no argument.""" @@ -2723,8 +1969,7 @@ class TestBase(Base):      def build(self, architecture=None, compiler=None, dictionary=None, clean=True):          """Platform specific way to build the default binaries."""          module = builder_module() -        if target_is_android(): -            dictionary = append_android_envs(dictionary) +        dictionary = lldbplatformutil.finalize_build_dictionary(dictionary)          if self.debug_info is None:              return self.buildDefault(architecture, compiler, dictionary, clean)          elif self.debug_info == "dsym": @@ -2733,9 +1978,17 @@ class TestBase(Base):              return self.buildDwarf(architecture, compiler, dictionary, clean)          elif self.debug_info == "dwo":              return self.buildDwo(architecture, compiler, dictionary, clean) +        elif self.debug_info == "gmodules": +            return self.buildGModules(architecture, compiler, dictionary, clean)          else:              self.fail("Can't build for debug info: %s" % self.debug_info) +    def run_platform_command(self, cmd): +        platform = self.dbg.GetSelectedPlatform() +        shell_command = lldb.SBPlatformShellCommand(cmd) +        err = platform.Run(shell_command) +        return (err, shell_command.GetStatus(), shell_command.GetOutput()) +      # =================================================      # Misc. helper methods for debugging test execution      # ================================================= @@ -2780,4 +2033,17 @@ class TestBase(Base):      @classmethod      def RemoveTempFile(cls, file):          if os.path.exists(file): +            remove_file(file) + +# On Windows, the first attempt to delete a recently-touched file can fail +# because of a race with antimalware scanners.  This function will detect a +# failure and retry. +def remove_file(file, num_retries = 1, sleep_duration = 0.5): +    for i in range(num_retries+1): +        try:              os.remove(file) +            return True +        except: +            time.sleep(sleep_duration) +            continue +    return False | 
