|  | """ | 
|  | A simple testing framework for lldb using python's unit testing framework. | 
|  |  | 
|  | Tests for lldb are written as python scripts which take advantage of the script | 
|  | bridging provided by LLDB.framework to interact with lldb core. | 
|  |  | 
|  | A specific naming pattern is followed by the .py script to be recognized as | 
|  | a module which implements a test scenario, namely, Test*.py. | 
|  |  | 
|  | To specify the directories where "Test*.py" python test scripts are located, | 
|  | you need to pass in a list of directory names.  By default, the current | 
|  | working directory is searched if nothing is specified on the command line. | 
|  |  | 
|  | Type: | 
|  |  | 
|  | ./dotest.py -h | 
|  |  | 
|  | for available options. | 
|  | """ | 
|  |  | 
|  | from __future__ import absolute_import | 
|  | from __future__ import print_function | 
|  |  | 
|  | # System modules | 
|  | import atexit | 
|  | import datetime | 
|  | import errno | 
|  | import logging | 
|  | import os | 
|  | import platform | 
|  | import re | 
|  | import signal | 
|  | import subprocess | 
|  | import sys | 
|  |  | 
|  | # Third-party modules | 
|  | import six | 
|  | import unittest2 | 
|  |  | 
|  | # LLDB Modules | 
|  | import lldbsuite | 
|  | from . import configuration | 
|  | from . import dotest_args | 
|  | from . import lldbtest_config | 
|  | from . import test_categories | 
|  | from lldbsuite.test_event import formatter | 
|  | from . import test_result | 
|  | from lldbsuite.test_event.event_builder import EventBuilder | 
|  | from ..support import seven | 
|  |  | 
|  | def get_dotest_invocation(): | 
|  | return ' '.join(sys.argv) | 
|  |  | 
|  |  | 
|  | def is_exe(fpath): | 
|  | """Returns true if fpath is an executable.""" | 
|  | if fpath == None: | 
|  | return False | 
|  | return os.path.isfile(fpath) and os.access(fpath, os.X_OK) | 
|  |  | 
|  |  | 
|  | def which(program): | 
|  | """Returns the full path to a program; None otherwise.""" | 
|  | fpath, _ = os.path.split(program) | 
|  | if fpath: | 
|  | if is_exe(program): | 
|  | return program | 
|  | else: | 
|  | for path in os.environ["PATH"].split(os.pathsep): | 
|  | exe_file = os.path.join(path, program) | 
|  | if is_exe(exe_file): | 
|  | return exe_file | 
|  | return None | 
|  |  | 
|  |  | 
|  | def usage(parser): | 
|  | parser.print_help() | 
|  | if configuration.verbose > 0: | 
|  | print(""" | 
|  | Examples: | 
|  |  | 
|  | This is an example of using the -f option to pinpoint to a specific test class | 
|  | and test method to be run: | 
|  |  | 
|  | $ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command | 
|  | ---------------------------------------------------------------------- | 
|  | Collected 1 test | 
|  |  | 
|  | test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase) | 
|  | Test 'frame variable this' when stopped on a class constructor. ... ok | 
|  |  | 
|  | ---------------------------------------------------------------------- | 
|  | Ran 1 test in 1.396s | 
|  |  | 
|  | OK | 
|  |  | 
|  | And this is an example of using the -p option to run a single file (the filename | 
|  | matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'): | 
|  |  | 
|  | $ ./dotest.py -v -p ObjC | 
|  | ---------------------------------------------------------------------- | 
|  | Collected 4 tests | 
|  |  | 
|  | test_break_with_dsym (TestObjCMethods.FoundationTestCase) | 
|  | Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok | 
|  | test_break_with_dwarf (TestObjCMethods.FoundationTestCase) | 
|  | Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok | 
|  | test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase) | 
|  | Lookup objective-c data types and evaluate expressions. ... ok | 
|  | test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase) | 
|  | Lookup objective-c data types and evaluate expressions. ... ok | 
|  |  | 
|  | ---------------------------------------------------------------------- | 
|  | Ran 4 tests in 16.661s | 
|  |  | 
|  | OK | 
|  |  | 
|  | Running of this script also sets up the LLDB_TEST environment variable so that | 
|  | individual test cases can locate their supporting files correctly.  The script | 
|  | tries to set up Python's search paths for modules by looking at the build tree | 
|  | relative to this script.  See also the '-i' option in the following example. | 
|  |  | 
|  | Finally, this is an example of using the lldb.py module distributed/installed by | 
|  | Xcode4 to run against the tests under the 'forward' directory, and with the '-w' | 
|  | option to add some delay between two tests.  It uses ARCH=x86_64 to specify that | 
|  | as the architecture and CC=clang to specify the compiler used for the test run: | 
|  |  | 
|  | $ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward | 
|  |  | 
|  | Session logs for test failures/errors will go into directory '2010-11-11-13_56_16' | 
|  | ---------------------------------------------------------------------- | 
|  | Collected 2 tests | 
|  |  | 
|  | test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase) | 
|  | Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok | 
|  | test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase) | 
|  | Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok | 
|  |  | 
|  | ---------------------------------------------------------------------- | 
|  | Ran 2 tests in 5.659s | 
|  |  | 
|  | OK | 
|  |  | 
|  | The 'Session ...' verbiage is recently introduced (see also the '-s' option) to | 
|  | notify the directory containing the session logs for test failures or errors. | 
|  | In case there is any test failure/error, a similar message is appended at the | 
|  | end of the stderr output for your convenience. | 
|  |  | 
|  | ENABLING LOGS FROM TESTS | 
|  |  | 
|  | Option 1: | 
|  |  | 
|  | Writing logs into different files per test case:: | 
|  |  | 
|  | $ ./dotest.py --channel "lldb all" | 
|  |  | 
|  | $ ./dotest.py --channel "lldb all" --channel "gdb-remote packets" | 
|  |  | 
|  | These log files are written to: | 
|  |  | 
|  | <session-dir>/<test-id>-host.log (logs from lldb host process) | 
|  | <session-dir>/<test-id>-server.log (logs from debugserver/lldb-server) | 
|  | <session-dir>/<test-id>-<test-result>.log (console logs) | 
|  |  | 
|  | By default, logs from successful runs are deleted.  Use the --log-success flag | 
|  | to create reference logs for debugging. | 
|  |  | 
|  | $ ./dotest.py --log-success | 
|  |  | 
|  | """) | 
|  | sys.exit(0) | 
|  |  | 
|  |  | 
|  | def parseExclusion(exclusion_file): | 
|  | """Parse an exclusion file, of the following format, where | 
|  | 'skip files', 'skip methods', 'xfail files', and 'xfail methods' | 
|  | are the possible list heading values: | 
|  |  | 
|  | skip files | 
|  | <file name> | 
|  | <file name> | 
|  |  | 
|  | xfail methods | 
|  | <method name> | 
|  | """ | 
|  | excl_type = None | 
|  |  | 
|  | with open(exclusion_file) as f: | 
|  | for line in f: | 
|  | line = line.strip() | 
|  | if not excl_type: | 
|  | excl_type = line | 
|  | continue | 
|  |  | 
|  | if not line: | 
|  | excl_type = None | 
|  | elif excl_type == 'skip': | 
|  | if not configuration.skip_tests: | 
|  | configuration.skip_tests = [] | 
|  | configuration.skip_tests.append(line) | 
|  | elif excl_type == 'xfail': | 
|  | if not configuration.xfail_tests: | 
|  | configuration.xfail_tests = [] | 
|  | configuration.xfail_tests.append(line) | 
|  |  | 
|  |  | 
|  | def parseOptionsAndInitTestdirs(): | 
|  | """Initialize the list of directories containing our unittest scripts. | 
|  |  | 
|  | '-h/--help as the first option prints out usage info and exit the program. | 
|  | """ | 
|  |  | 
|  | do_help = False | 
|  |  | 
|  | platform_system = platform.system() | 
|  | platform_machine = platform.machine() | 
|  |  | 
|  | try: | 
|  | parser = dotest_args.create_parser() | 
|  | args = parser.parse_args() | 
|  | except: | 
|  | print(get_dotest_invocation()) | 
|  | raise | 
|  |  | 
|  | if args.unset_env_varnames: | 
|  | for env_var in args.unset_env_varnames: | 
|  | if env_var in os.environ: | 
|  | # From Python Doc: When unsetenv() is supported, deletion of items in os.environ | 
|  | # is automatically translated into a corresponding call to | 
|  | # unsetenv(). | 
|  | del os.environ[env_var] | 
|  | # os.unsetenv(env_var) | 
|  |  | 
|  | if args.set_env_vars: | 
|  | for env_var in args.set_env_vars: | 
|  | parts = env_var.split('=', 1) | 
|  | if len(parts) == 1: | 
|  | os.environ[parts[0]] = "" | 
|  | else: | 
|  | os.environ[parts[0]] = parts[1] | 
|  |  | 
|  | if args.set_inferior_env_vars: | 
|  | lldbtest_config.inferior_env = ' '.join(args.set_inferior_env_vars) | 
|  |  | 
|  | # Only print the args if being verbose. | 
|  | if args.v: | 
|  | print(get_dotest_invocation()) | 
|  |  | 
|  | if args.h: | 
|  | do_help = True | 
|  |  | 
|  | if args.compiler: | 
|  | configuration.compiler = os.path.realpath(args.compiler) | 
|  | if not is_exe(configuration.compiler): | 
|  | configuration.compiler = which(args.compiler) | 
|  | if not is_exe(configuration.compiler): | 
|  | logging.error( | 
|  | '%s is not a valid compiler executable; aborting...', | 
|  | args.compiler) | 
|  | sys.exit(-1) | 
|  | else: | 
|  | # Use a compiler appropriate appropriate for the Apple SDK if one was | 
|  | # specified | 
|  | if platform_system == 'Darwin' and args.apple_sdk: | 
|  | configuration.compiler = seven.get_command_output( | 
|  | 'xcrun -sdk "%s" -find clang 2> /dev/null' % | 
|  | (args.apple_sdk)) | 
|  | else: | 
|  | # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first | 
|  | candidateCompilers = ['clang-3.5', 'clang', 'gcc'] | 
|  | for candidate in candidateCompilers: | 
|  | if which(candidate): | 
|  | configuration.compiler = candidate | 
|  | break | 
|  |  | 
|  | if args.dsymutil: | 
|  | os.environ['DSYMUTIL'] = args.dsymutil | 
|  | elif platform_system == 'Darwin': | 
|  | os.environ['DSYMUTIL'] = seven.get_command_output( | 
|  | 'xcrun -find -toolchain default dsymutil') | 
|  |  | 
|  | if args.filecheck: | 
|  | # The lldb-dotest script produced by the CMake build passes in a path | 
|  | # to a working FileCheck binary. So does one specific Xcode project | 
|  | # target. However, when invoking dotest.py directly, a valid --filecheck | 
|  | # option needs to be given. | 
|  | configuration.filecheck = os.path.abspath(args.filecheck) | 
|  |  | 
|  | if not configuration.get_filecheck_path(): | 
|  | logging.warning('No valid FileCheck executable; some tests may fail...') | 
|  | logging.warning('(Double-check the --filecheck argument to dotest.py)') | 
|  |  | 
|  | if args.channels: | 
|  | lldbtest_config.channels = args.channels | 
|  |  | 
|  | if args.log_success: | 
|  | lldbtest_config.log_success = args.log_success | 
|  |  | 
|  | if args.out_of_tree_debugserver: | 
|  | lldbtest_config.out_of_tree_debugserver = args.out_of_tree_debugserver | 
|  |  | 
|  | # Set SDKROOT if we are using an Apple SDK | 
|  | if platform_system == 'Darwin' and args.apple_sdk: | 
|  | os.environ['SDKROOT'] = seven.get_command_output( | 
|  | 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % | 
|  | (args.apple_sdk)) | 
|  |  | 
|  | if args.arch: | 
|  | configuration.arch = args.arch | 
|  | if configuration.arch.startswith( | 
|  | 'arm') and platform_system == 'Darwin' and not args.apple_sdk: | 
|  | os.environ['SDKROOT'] = seven.get_command_output( | 
|  | 'xcrun --sdk iphoneos.internal --show-sdk-path 2> /dev/null') | 
|  | if not os.path.exists(os.environ['SDKROOT']): | 
|  | os.environ['SDKROOT'] = seven.get_command_output( | 
|  | 'xcrun --sdk iphoneos --show-sdk-path 2> /dev/null') | 
|  | else: | 
|  | configuration.arch = platform_machine | 
|  |  | 
|  | if args.categoriesList: | 
|  | configuration.categoriesList = set( | 
|  | test_categories.validate( | 
|  | args.categoriesList, False)) | 
|  | configuration.useCategories = True | 
|  | else: | 
|  | configuration.categoriesList = [] | 
|  |  | 
|  | if args.skipCategories: | 
|  | configuration.skipCategories += test_categories.validate( | 
|  | args.skipCategories, False) | 
|  |  | 
|  | if args.E: | 
|  | os.environ['CFLAGS_EXTRAS'] = args.E | 
|  |  | 
|  | if args.dwarf_version: | 
|  | configuration.dwarf_version = args.dwarf_version | 
|  | # We cannot modify CFLAGS_EXTRAS because they're used in test cases | 
|  | # that explicitly require no debug info. | 
|  | os.environ['CFLAGS'] = '-gdwarf-{}'.format(configuration.dwarf_version) | 
|  |  | 
|  | if args.d: | 
|  | sys.stdout.write( | 
|  | "Suspending the process %d to wait for debugger to attach...\n" % | 
|  | os.getpid()) | 
|  | sys.stdout.flush() | 
|  | os.kill(os.getpid(), signal.SIGSTOP) | 
|  |  | 
|  | if args.f: | 
|  | if any([x.startswith('-') for x in args.f]): | 
|  | usage(parser) | 
|  | configuration.filters.extend(args.f) | 
|  |  | 
|  | if args.framework: | 
|  | configuration.lldbFrameworkPath = args.framework | 
|  |  | 
|  | if args.executable: | 
|  | # lldb executable is passed explicitly | 
|  | lldbtest_config.lldbExec = os.path.realpath(args.executable) | 
|  | if not is_exe(lldbtest_config.lldbExec): | 
|  | lldbtest_config.lldbExec = which(args.executable) | 
|  | if not is_exe(lldbtest_config.lldbExec): | 
|  | logging.error( | 
|  | '%s is not a valid executable to test; aborting...', | 
|  | args.executable) | 
|  | sys.exit(-1) | 
|  |  | 
|  | if args.server: | 
|  | os.environ['LLDB_DEBUGSERVER_PATH'] = args.server | 
|  |  | 
|  | if args.excluded: | 
|  | for excl_file in args.excluded: | 
|  | parseExclusion(excl_file) | 
|  |  | 
|  | if args.p: | 
|  | if args.p.startswith('-'): | 
|  | usage(parser) | 
|  | configuration.regexp = args.p | 
|  |  | 
|  | if args.s: | 
|  | configuration.sdir_name = args.s | 
|  | else: | 
|  | timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S") | 
|  | configuration.sdir_name = os.path.join(os.getcwd(), timestamp_started) | 
|  |  | 
|  | configuration.session_file_format = args.session_file_format | 
|  |  | 
|  | if args.t: | 
|  | os.environ['LLDB_COMMAND_TRACE'] = 'YES' | 
|  |  | 
|  | if args.v: | 
|  | configuration.verbose = 2 | 
|  |  | 
|  | # argparse makes sure we have a number | 
|  | if args.sharp: | 
|  | configuration.count = args.sharp | 
|  |  | 
|  | if sys.platform.startswith('win32'): | 
|  | os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str( | 
|  | args.disable_crash_dialog) | 
|  | os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True) | 
|  |  | 
|  | if do_help: | 
|  | usage(parser) | 
|  |  | 
|  | if args.results_file: | 
|  | configuration.results_filename = args.results_file | 
|  |  | 
|  | if args.results_formatter: | 
|  | configuration.results_formatter_name = args.results_formatter | 
|  | if args.results_formatter_options: | 
|  | configuration.results_formatter_options = args.results_formatter_options | 
|  |  | 
|  | # Default to using the BasicResultsFormatter if no formatter is specified. | 
|  | if configuration.results_formatter_name is None: | 
|  | configuration.results_formatter_name = ( | 
|  | "lldbsuite.test_event.formatter.results_formatter.ResultsFormatter") | 
|  |  | 
|  | # rerun-related arguments | 
|  | configuration.rerun_all_issues = args.rerun_all_issues | 
|  |  | 
|  | if args.lldb_platform_name: | 
|  | configuration.lldb_platform_name = args.lldb_platform_name | 
|  | if args.lldb_platform_url: | 
|  | configuration.lldb_platform_url = args.lldb_platform_url | 
|  | if args.lldb_platform_working_dir: | 
|  | configuration.lldb_platform_working_dir = args.lldb_platform_working_dir | 
|  | if args.test_build_dir: | 
|  | configuration.test_build_dir = args.test_build_dir | 
|  | if args.lldb_module_cache_dir: | 
|  | configuration.lldb_module_cache_dir = args.lldb_module_cache_dir | 
|  | else: | 
|  | configuration.lldb_module_cache_dir = os.path.join( | 
|  | configuration.test_build_dir, 'module-cache-lldb') | 
|  | if args.clang_module_cache_dir: | 
|  | configuration.clang_module_cache_dir = args.clang_module_cache_dir | 
|  | else: | 
|  | configuration.clang_module_cache_dir = os.path.join( | 
|  | configuration.test_build_dir, 'module-cache-clang') | 
|  |  | 
|  | os.environ['CLANG_MODULE_CACHE_DIR'] = configuration.clang_module_cache_dir | 
|  |  | 
|  | # Gather all the dirs passed on the command line. | 
|  | if len(args.args) > 0: | 
|  | configuration.testdirs = [os.path.realpath(os.path.abspath(x)) for x in args.args] | 
|  |  | 
|  | lldbtest_config.codesign_identity = args.codesign_identity | 
|  |  | 
|  |  | 
|  | def setupTestResults(): | 
|  | """Sets up test results-related objects based on arg settings.""" | 
|  | # Setup the results formatter configuration. | 
|  | formatter_config = formatter.FormatterConfig() | 
|  | formatter_config.filename = configuration.results_filename | 
|  | formatter_config.formatter_name = configuration.results_formatter_name | 
|  | formatter_config.formatter_options = ( | 
|  | configuration.results_formatter_options) | 
|  |  | 
|  | # Create the results formatter. | 
|  | formatter_spec = formatter.create_results_formatter( | 
|  | formatter_config) | 
|  | if formatter_spec is not None and formatter_spec.formatter is not None: | 
|  | configuration.results_formatter_object = formatter_spec.formatter | 
|  |  | 
|  | # Send an initialize message to the formatter. | 
|  | initialize_event = EventBuilder.bare_event("initialize") | 
|  | initialize_event["worker_count"] = 1 | 
|  |  | 
|  | formatter_spec.formatter.handle_event(initialize_event) | 
|  |  | 
|  | # Make sure we clean up the formatter on shutdown. | 
|  | if formatter_spec.cleanup_func is not None: | 
|  | atexit.register(formatter_spec.cleanup_func) | 
|  |  | 
|  |  | 
|  | def setupSysPath(): | 
|  | """ | 
|  | Add LLDB.framework/Resources/Python to the search paths for modules. | 
|  | As a side effect, we also discover the 'lldb' executable and export it here. | 
|  | """ | 
|  |  | 
|  | # Get the directory containing the current script. | 
|  | if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ: | 
|  | scriptPath = os.environ["DOTEST_SCRIPT_DIR"] | 
|  | else: | 
|  | scriptPath = os.path.dirname(os.path.realpath(__file__)) | 
|  | if not scriptPath.endswith('test'): | 
|  | print("This script expects to reside in lldb's test directory.") | 
|  | sys.exit(-1) | 
|  |  | 
|  | os.environ["LLDB_TEST"] = scriptPath | 
|  |  | 
|  | # Set up the root build directory. | 
|  | builddir = configuration.test_build_dir | 
|  | if not configuration.test_build_dir: | 
|  | raise Exception("test_build_dir is not set") | 
|  | os.environ["LLDB_BUILD"] = os.path.abspath(configuration.test_build_dir) | 
|  |  | 
|  | # Set up the LLDB_SRC environment variable, so that the tests can locate | 
|  | # the LLDB source code. | 
|  | os.environ["LLDB_SRC"] = lldbsuite.lldb_root | 
|  |  | 
|  | pluginPath = os.path.join(scriptPath, 'plugins') | 
|  | toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode') | 
|  | toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server') | 
|  |  | 
|  | # Insert script dir, plugin dir and lldb-server dir to the sys.path. | 
|  | sys.path.insert(0, pluginPath) | 
|  | # Adding test/tools/lldb-vscode to the path makes it easy to | 
|  | # "import lldb_vscode_testcase" from the VSCode tests | 
|  | sys.path.insert(0, toolsLLDBVSCode) | 
|  | # Adding test/tools/lldb-server to the path makes it easy | 
|  | sys.path.insert(0, toolsLLDBServerPath) | 
|  | # to "import lldbgdbserverutils" from the lldb-server tests | 
|  |  | 
|  | # This is the root of the lldb git/svn checkout | 
|  | # When this changes over to a package instead of a standalone script, this | 
|  | # will be `lldbsuite.lldb_root` | 
|  | lldbRootDirectory = lldbsuite.lldb_root | 
|  |  | 
|  | # Some of the tests can invoke the 'lldb' command directly. | 
|  | # We'll try to locate the appropriate executable right here. | 
|  |  | 
|  | # The lldb executable can be set from the command line | 
|  | # if it's not set, we try to find it now | 
|  | # first, we try the environment | 
|  | if not lldbtest_config.lldbExec: | 
|  | # First, you can define an environment variable LLDB_EXEC specifying the | 
|  | # full pathname of the lldb executable. | 
|  | if "LLDB_EXEC" in os.environ: | 
|  | lldbtest_config.lldbExec = os.environ["LLDB_EXEC"] | 
|  |  | 
|  | if not lldbtest_config.lldbExec: | 
|  | # Last, check the path | 
|  | lldbtest_config.lldbExec = which('lldb') | 
|  |  | 
|  | if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec): | 
|  | print( | 
|  | "'{}' is not a path to a valid executable".format( | 
|  | lldbtest_config.lldbExec)) | 
|  | lldbtest_config.lldbExec = None | 
|  |  | 
|  | if not lldbtest_config.lldbExec: | 
|  | print("The 'lldb' executable cannot be located.  Some of the tests may not be run as a result.") | 
|  | sys.exit(-1) | 
|  |  | 
|  | # confusingly, this is the "bin" directory | 
|  | lldbLibDir = os.path.dirname(lldbtest_config.lldbExec) | 
|  | os.environ["LLDB_LIB_DIR"] = lldbLibDir | 
|  | lldbImpLibDir = os.path.join( | 
|  | lldbLibDir, | 
|  | '..', | 
|  | 'lib') if sys.platform.startswith('win32') else lldbLibDir | 
|  | os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir | 
|  | print("LLDB library dir:", os.environ["LLDB_LIB_DIR"]) | 
|  | print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"]) | 
|  | os.system('%s -v' % lldbtest_config.lldbExec) | 
|  |  | 
|  | lldbDir = os.path.dirname(lldbtest_config.lldbExec) | 
|  |  | 
|  | lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode") | 
|  | if is_exe(lldbVSCodeExec): | 
|  | os.environ["LLDBVSCODE_EXEC"] = lldbVSCodeExec | 
|  | else: | 
|  | if not configuration.shouldSkipBecauseOfCategories(["lldb-vscode"]): | 
|  | print( | 
|  | "The 'lldb-vscode' executable cannot be located.  The lldb-vscode tests can not be run as a result.") | 
|  | configuration.skipCategories.append("lldb-vscode") | 
|  |  | 
|  | lldbPythonDir = None  # The directory that contains 'lldb/__init__.py' | 
|  | if not configuration.lldbFrameworkPath and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")): | 
|  | configuration.lldbFrameworkPath = os.path.join(lldbLibDir, "LLDB.framework") | 
|  | if configuration.lldbFrameworkPath: | 
|  | lldbtest_config.lldbFrameworkPath = configuration.lldbFrameworkPath | 
|  | candidatePath = os.path.join( | 
|  | configuration.lldbFrameworkPath, 'Resources', 'Python') | 
|  | if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')): | 
|  | lldbPythonDir = candidatePath | 
|  | if not lldbPythonDir: | 
|  | print( | 
|  | 'Resources/Python/lldb/__init__.py was not found in ' + | 
|  | configuration.lldbFrameworkPath) | 
|  | sys.exit(-1) | 
|  | else: | 
|  | # If our lldb supports the -P option, use it to find the python path: | 
|  | init_in_python_dir = os.path.join('lldb', '__init__.py') | 
|  |  | 
|  | lldb_dash_p_result = subprocess.check_output( | 
|  | [lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True) | 
|  |  | 
|  | if lldb_dash_p_result and not lldb_dash_p_result.startswith( | 
|  | ("<", "lldb: invalid option:")) and not lldb_dash_p_result.startswith("Traceback"): | 
|  | lines = lldb_dash_p_result.splitlines() | 
|  |  | 
|  | # Workaround for readline vs libedit issue on FreeBSD.  If stdout | 
|  | # is not a terminal Python executes | 
|  | #     rl_variable_bind ("enable-meta-key", "off"); | 
|  | # This produces a warning with FreeBSD's libedit because the | 
|  | # enable-meta-key variable is unknown.  Not an issue on Apple | 
|  | # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__ | 
|  | # around the call.  See http://bugs.python.org/issue19884 for more | 
|  | # information.  For now we just discard the warning output. | 
|  | if len(lines) >= 1 and lines[0].startswith( | 
|  | "bind: Invalid command"): | 
|  | lines.pop(0) | 
|  |  | 
|  | # Taking the last line because lldb outputs | 
|  | # 'Cannot read termcap database;\nusing dumb terminal settings.\n' | 
|  | # before the path | 
|  | if len(lines) >= 1 and os.path.isfile( | 
|  | os.path.join(lines[-1], init_in_python_dir)): | 
|  | lldbPythonDir = lines[-1] | 
|  | if "freebsd" in sys.platform or "linux" in sys.platform: | 
|  | os.environ['LLDB_LIB_DIR'] = os.path.join( | 
|  | lldbPythonDir, '..', '..') | 
|  |  | 
|  | if not lldbPythonDir: | 
|  | print( | 
|  | "Unable to load lldb extension module.  Possible reasons for this include:") | 
|  | print("  1) LLDB was built with LLDB_DISABLE_PYTHON=1") | 
|  | print( | 
|  | "  2) PYTHONPATH and PYTHONHOME are not set correctly.  PYTHONHOME should refer to") | 
|  | print( | 
|  | "     the version of Python that LLDB built and linked against, and PYTHONPATH") | 
|  | print( | 
|  | "     should contain the Lib directory for the same python distro, as well as the") | 
|  | print("     location of LLDB\'s site-packages folder.") | 
|  | print( | 
|  | "  3) A different version of Python than that which was built against is exported in") | 
|  | print("     the system\'s PATH environment variable, causing conflicts.") | 
|  | print( | 
|  | "  4) The executable '%s' could not be found.  Please check " % | 
|  | lldbtest_config.lldbExec) | 
|  | print("     that it exists and is executable.") | 
|  |  | 
|  | if lldbPythonDir: | 
|  | lldbPythonDir = os.path.normpath(lldbPythonDir) | 
|  | # Some of the code that uses this path assumes it hasn't resolved the Versions... link. | 
|  | # If the path we've constructed looks like that, then we'll strip out | 
|  | # the Versions/A part. | 
|  | (before, frameWithVersion, after) = lldbPythonDir.rpartition( | 
|  | "LLDB.framework/Versions/A") | 
|  | if frameWithVersion != "": | 
|  | lldbPythonDir = before + "LLDB.framework" + after | 
|  |  | 
|  | lldbPythonDir = os.path.abspath(lldbPythonDir) | 
|  |  | 
|  | # If tests need to find LLDB_FRAMEWORK, now they can do it | 
|  | os.environ["LLDB_FRAMEWORK"] = os.path.dirname( | 
|  | os.path.dirname(lldbPythonDir)) | 
|  |  | 
|  | # This is to locate the lldb.py module.  Insert it right after | 
|  | # sys.path[0]. | 
|  | sys.path[1:1] = [lldbPythonDir] | 
|  |  | 
|  |  | 
|  | def visit_file(dir, name): | 
|  | # Try to match the regexp pattern, if specified. | 
|  | if configuration.regexp: | 
|  | if not re.search(configuration.regexp, name): | 
|  | # We didn't match the regex, we're done. | 
|  | return | 
|  |  | 
|  | if configuration.skip_tests: | 
|  | for file_regexp in configuration.skip_tests: | 
|  | if re.search(file_regexp, name): | 
|  | return | 
|  |  | 
|  | # We found a match for our test.  Add it to the suite. | 
|  |  | 
|  | # Update the sys.path first. | 
|  | if not sys.path.count(dir): | 
|  | sys.path.insert(0, dir) | 
|  | base = os.path.splitext(name)[0] | 
|  |  | 
|  | # Thoroughly check the filterspec against the base module and admit | 
|  | # the (base, filterspec) combination only when it makes sense. | 
|  |  | 
|  | def check(obj, parts): | 
|  | for part in parts: | 
|  | try: | 
|  | parent, obj = obj, getattr(obj, part) | 
|  | except AttributeError: | 
|  | # The filterspec has failed. | 
|  | return False | 
|  | return True | 
|  |  | 
|  | module = __import__(base) | 
|  |  | 
|  | def iter_filters(): | 
|  | for filterspec in configuration.filters: | 
|  | parts = filterspec.split('.') | 
|  | if check(module, parts): | 
|  | yield filterspec | 
|  | elif parts[0] == base and len(parts) > 1 and check(module, parts[1:]): | 
|  | yield '.'.join(parts[1:]) | 
|  | else: | 
|  | for key,value in module.__dict__.items(): | 
|  | if check(value, parts): | 
|  | yield key + '.' + filterspec | 
|  |  | 
|  | filtered = False | 
|  | for filterspec in iter_filters(): | 
|  | filtered = True | 
|  | print("adding filter spec %s to module %s" % (filterspec, repr(module))) | 
|  | tests = unittest2.defaultTestLoader.loadTestsFromName(filterspec, module) | 
|  | configuration.suite.addTests(tests) | 
|  |  | 
|  | # Forgo this module if the (base, filterspec) combo is invalid | 
|  | if configuration.filters and not filtered: | 
|  | return | 
|  |  | 
|  | if not filtered: | 
|  | # Add the entire file's worth of tests since we're not filtered. | 
|  | # Also the fail-over case when the filterspec branch | 
|  | # (base, filterspec) combo doesn't make sense. | 
|  | configuration.suite.addTests( | 
|  | unittest2.defaultTestLoader.loadTestsFromName(base)) | 
|  |  | 
|  |  | 
|  | def visit(prefix, dir, names): | 
|  | """Visitor function for os.path.walk(path, visit, arg).""" | 
|  |  | 
|  | dir_components = set(dir.split(os.sep)) | 
|  | excluded_components = set(['.svn', '.git']) | 
|  | if dir_components.intersection(excluded_components): | 
|  | return | 
|  |  | 
|  | # Gather all the Python test file names that follow the Test*.py pattern. | 
|  | python_test_files = [ | 
|  | name | 
|  | for name in names | 
|  | if name.endswith('.py') and name.startswith(prefix)] | 
|  |  | 
|  | # Visit all the python test files. | 
|  | for name in python_test_files: | 
|  | try: | 
|  | # Ensure we error out if we have multiple tests with the same | 
|  | # base name. | 
|  | # Future improvement: find all the places where we work with base | 
|  | # names and convert to full paths.  We have directory structure | 
|  | # to disambiguate these, so we shouldn't need this constraint. | 
|  | if name in configuration.all_tests: | 
|  | raise Exception("Found multiple tests with the name %s" % name) | 
|  | configuration.all_tests.add(name) | 
|  |  | 
|  | # Run the relevant tests in the python file. | 
|  | visit_file(dir, name) | 
|  | except Exception as ex: | 
|  | # Convert this exception to a test event error for the file. | 
|  | test_filename = os.path.abspath(os.path.join(dir, name)) | 
|  | if configuration.results_formatter_object is not None: | 
|  | # Grab the backtrace for the exception. | 
|  | import traceback | 
|  | backtrace = traceback.format_exc() | 
|  |  | 
|  | # Generate the test event. | 
|  | configuration.results_formatter_object.handle_event( | 
|  | EventBuilder.event_for_job_test_add_error( | 
|  | test_filename, ex, backtrace)) | 
|  | raise | 
|  |  | 
|  |  | 
|  | def disabledynamics(): | 
|  | import lldb | 
|  | ci = lldb.DBG.GetCommandInterpreter() | 
|  | res = lldb.SBCommandReturnObject() | 
|  | ci.HandleCommand( | 
|  | "setting set target.prefer-dynamic-value no-dynamic-values", | 
|  | res, | 
|  | False) | 
|  | if not res.Succeeded(): | 
|  | raise Exception('disabling dynamic type support failed') | 
|  |  | 
|  |  | 
|  | # ======================================== # | 
|  | #                                          # | 
|  | # Execution of the test driver starts here # | 
|  | #                                          # | 
|  | # ======================================== # | 
|  |  | 
|  |  | 
|  | def checkDsymForUUIDIsNotOn(): | 
|  | cmd = ["defaults", "read", "com.apple.DebugSymbols"] | 
|  | process = subprocess.Popen( | 
|  | cmd, | 
|  | stdout=subprocess.PIPE, | 
|  | stderr=subprocess.STDOUT) | 
|  | cmd_output = process.stdout.read() | 
|  | output_str = cmd_output.decode("utf-8") | 
|  | if "DBGFileMappedPaths = " in output_str: | 
|  | print("%s =>" % ' '.join(cmd)) | 
|  | print(output_str) | 
|  | print( | 
|  | "Disable automatic lookup and caching of dSYMs before running the test suite!") | 
|  | print("Exiting...") | 
|  | sys.exit(0) | 
|  |  | 
|  |  | 
|  | def exitTestSuite(exitCode=None): | 
|  | import lldb | 
|  | lldb.SBDebugger.Terminate() | 
|  | if exitCode: | 
|  | sys.exit(exitCode) | 
|  |  | 
|  |  | 
|  | def getVersionForSDK(sdk): | 
|  | sdk = str.lower(sdk) | 
|  | full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk) | 
|  | basename = os.path.basename(full_path) | 
|  | basename = os.path.splitext(basename)[0] | 
|  | basename = str.lower(basename) | 
|  | ver = basename.replace(sdk, '') | 
|  | return ver | 
|  |  | 
|  |  | 
|  | def setDefaultTripleForPlatform(): | 
|  | if configuration.lldb_platform_name == 'ios-simulator': | 
|  | triple_str = 'x86_64-apple-ios%s' % ( | 
|  | getVersionForSDK('iphonesimulator')) | 
|  | os.environ['TRIPLE'] = triple_str | 
|  | return {'TRIPLE': triple_str} | 
|  | return {} | 
|  |  | 
|  |  | 
|  | def checkCompiler(): | 
|  | # Add some intervention here to sanity check that the compiler requested is sane. | 
|  | # If found not to be an executable program, we abort. | 
|  | c = configuration.compiler | 
|  | if which(c): | 
|  | return | 
|  |  | 
|  | if not sys.platform.startswith("darwin"): | 
|  | raise Exception(c + " is not a valid compiler") | 
|  |  | 
|  | pipe = subprocess.Popen( | 
|  | ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | 
|  | cmd_output = pipe.stdout.read() | 
|  | if not cmd_output or "not found" in cmd_output: | 
|  | raise Exception(c + " is not a valid compiler") | 
|  |  | 
|  | configuration.compiler = cmd_output.split('\n')[0] | 
|  | print("'xcrun -find %s' returning %s" % (c, configuration.compiler)) | 
|  |  | 
|  | def canRunLibcxxTests(): | 
|  | from lldbsuite.test import lldbplatformutil | 
|  |  | 
|  | platform = lldbplatformutil.getPlatform() | 
|  |  | 
|  | if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin(): | 
|  | return True, "libc++ always present" | 
|  |  | 
|  | if platform == "linux": | 
|  | if not os.path.isdir("/usr/include/c++/v1"): | 
|  | return False, "Unable to find libc++ installation" | 
|  | return True, "Headers found, let's hope they work" | 
|  |  | 
|  | return False, "Don't know how to build with libc++ on %s" % platform | 
|  |  | 
|  | def checkLibcxxSupport(): | 
|  | result, reason = canRunLibcxxTests() | 
|  | if result: | 
|  | return # libc++ supported | 
|  | if "libc++" in configuration.categoriesList: | 
|  | return # libc++ category explicitly requested, let it run. | 
|  | print("Libc++ tests will not be run because: " + reason) | 
|  | configuration.skipCategories.append("libc++") | 
|  |  | 
|  | def canRunLibstdcxxTests(): | 
|  | from lldbsuite.test import lldbplatformutil | 
|  |  | 
|  | platform = lldbplatformutil.getPlatform() | 
|  | if lldbplatformutil.target_is_android(): | 
|  | platform = "android" | 
|  | if platform == "linux": | 
|  | return True, "libstdcxx always present" | 
|  | return False, "Don't know how to build with libstdcxx on %s" % platform | 
|  |  | 
|  | def checkLibstdcxxSupport(): | 
|  | result, reason = canRunLibstdcxxTests() | 
|  | if result: | 
|  | return # libstdcxx supported | 
|  | if "libstdcxx" in configuration.categoriesList: | 
|  | return # libstdcxx category explicitly requested, let it run. | 
|  | print("libstdcxx tests will not be run because: " + reason) | 
|  | configuration.skipCategories.append("libstdcxx") | 
|  |  | 
|  | def canRunWatchpointTests(): | 
|  | from lldbsuite.test import lldbplatformutil | 
|  |  | 
|  | platform = lldbplatformutil.getPlatform() | 
|  | if platform == "netbsd": | 
|  | if os.geteuid() == 0: | 
|  | return True, "root can always write dbregs" | 
|  | try: | 
|  | output = subprocess.check_output(["/sbin/sysctl", "-n", | 
|  | "security.models.extensions.user_set_dbregs"]).decode().strip() | 
|  | if output == "1": | 
|  | return True, "security.models.extensions.user_set_dbregs enabled" | 
|  | except subprocess.CalledProcessError: | 
|  | pass | 
|  | return False, "security.models.extensions.user_set_dbregs disabled" | 
|  | return True, "watchpoint support available" | 
|  |  | 
|  | def checkWatchpointSupport(): | 
|  | result, reason = canRunWatchpointTests() | 
|  | if result: | 
|  | return # watchpoints supported | 
|  | if "watchpoint" in configuration.categoriesList: | 
|  | return # watchpoint category explicitly requested, let it run. | 
|  | print("watchpoint tests will not be run because: " + reason) | 
|  | configuration.skipCategories.append("watchpoint") | 
|  |  | 
|  | def checkDebugInfoSupport(): | 
|  | import lldb | 
|  |  | 
|  | platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2] | 
|  | compiler = configuration.compiler | 
|  | skipped = [] | 
|  | for cat in test_categories.debug_info_categories: | 
|  | if cat in configuration.categoriesList: | 
|  | continue # Category explicitly requested, let it run. | 
|  | if test_categories.is_supported_on_platform(cat, platform, compiler): | 
|  | continue | 
|  | configuration.skipCategories.append(cat) | 
|  | skipped.append(cat) | 
|  | if skipped: | 
|  | print("Skipping following debug info categories:", skipped) | 
|  |  | 
|  | def run_suite(): | 
|  | # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults | 
|  | # does not exist before proceeding to running the test suite. | 
|  | if sys.platform.startswith("darwin"): | 
|  | checkDsymForUUIDIsNotOn() | 
|  |  | 
|  | # Start the actions by first parsing the options while setting up the test | 
|  | # directories, followed by setting up the search paths for lldb utilities; | 
|  | # then, we walk the directory trees and collect the tests into our test suite. | 
|  | # | 
|  | parseOptionsAndInitTestdirs() | 
|  |  | 
|  | # Setup test results (test results formatter and output handling). | 
|  | setupTestResults() | 
|  |  | 
|  | setupSysPath() | 
|  |  | 
|  |  | 
|  | # For the time being, let's bracket the test runner within the | 
|  | # lldb.SBDebugger.Initialize()/Terminate() pair. | 
|  | import lldb | 
|  |  | 
|  | # Now we can also import lldbutil | 
|  | from lldbsuite.test import lldbutil | 
|  |  | 
|  | # Create a singleton SBDebugger in the lldb namespace. | 
|  | lldb.DBG = lldb.SBDebugger.Create() | 
|  |  | 
|  | if configuration.lldb_platform_name: | 
|  | print("Setting up remote platform '%s'" % | 
|  | (configuration.lldb_platform_name)) | 
|  | lldb.remote_platform = lldb.SBPlatform( | 
|  | configuration.lldb_platform_name) | 
|  | if not lldb.remote_platform.IsValid(): | 
|  | print( | 
|  | "error: unable to create the LLDB platform named '%s'." % | 
|  | (configuration.lldb_platform_name)) | 
|  | exitTestSuite(1) | 
|  | if configuration.lldb_platform_url: | 
|  | # We must connect to a remote platform if a LLDB platform URL was | 
|  | # specified | 
|  | print( | 
|  | "Connecting to remote platform '%s' at '%s'..." % | 
|  | (configuration.lldb_platform_name, configuration.lldb_platform_url)) | 
|  | platform_connect_options = lldb.SBPlatformConnectOptions( | 
|  | configuration.lldb_platform_url) | 
|  | err = lldb.remote_platform.ConnectRemote(platform_connect_options) | 
|  | if err.Success(): | 
|  | print("Connected.") | 
|  | else: | 
|  | print("error: failed to connect to remote platform using URL '%s': %s" % ( | 
|  | configuration.lldb_platform_url, err)) | 
|  | exitTestSuite(1) | 
|  | else: | 
|  | configuration.lldb_platform_url = None | 
|  |  | 
|  | platform_changes = setDefaultTripleForPlatform() | 
|  | first = True | 
|  | for key in platform_changes: | 
|  | if first: | 
|  | print("Environment variables setup for platform support:") | 
|  | first = False | 
|  | print("%s = %s" % (key, platform_changes[key])) | 
|  |  | 
|  | if configuration.lldb_platform_working_dir: | 
|  | print("Setting remote platform working directory to '%s'..." % | 
|  | (configuration.lldb_platform_working_dir)) | 
|  | error = lldb.remote_platform.MakeDirectory( | 
|  | configuration.lldb_platform_working_dir, 448)  # 448 = 0o700 | 
|  | if error.Fail(): | 
|  | raise Exception("making remote directory '%s': %s" % ( | 
|  | configuration.lldb_platform_working_dir, error)) | 
|  |  | 
|  | if not lldb.remote_platform.SetWorkingDirectory( | 
|  | configuration.lldb_platform_working_dir): | 
|  | raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir) | 
|  | lldb.DBG.SetSelectedPlatform(lldb.remote_platform) | 
|  | else: | 
|  | lldb.remote_platform = None | 
|  | configuration.lldb_platform_working_dir = None | 
|  | configuration.lldb_platform_url = None | 
|  |  | 
|  | # Set up the working directory. | 
|  | # Note that it's not dotest's job to clean this directory. | 
|  | build_dir = configuration.test_build_dir | 
|  | lldbutil.mkdir_p(build_dir) | 
|  |  | 
|  | target_platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2] | 
|  |  | 
|  | checkLibcxxSupport() | 
|  | checkLibstdcxxSupport() | 
|  | checkWatchpointSupport() | 
|  | checkDebugInfoSupport() | 
|  |  | 
|  | # Don't do debugserver tests on anything except OS X. | 
|  | configuration.dont_do_debugserver_test = "linux" in target_platform or "freebsd" in target_platform or "windows" in target_platform | 
|  |  | 
|  | # Don't do lldb-server (llgs) tests on anything except Linux and Windows. | 
|  | configuration.dont_do_llgs_test = not ("linux" in target_platform) and not ("windows" in target_platform) | 
|  |  | 
|  | # Collect tests from the specified testing directories. If a test | 
|  | # subdirectory filter is explicitly specified, limit the search to that | 
|  | # subdirectory. | 
|  | exclusive_test_subdir = configuration.get_absolute_path_to_exclusive_test_subdir() | 
|  | if exclusive_test_subdir: | 
|  | dirs_to_search = [exclusive_test_subdir] | 
|  | else: | 
|  | dirs_to_search = configuration.testdirs | 
|  | for testdir in dirs_to_search: | 
|  | for (dirpath, dirnames, filenames) in os.walk(testdir): | 
|  | visit('Test', dirpath, filenames) | 
|  |  | 
|  | # | 
|  | # Now that we have loaded all the test cases, run the whole test suite. | 
|  | # | 
|  |  | 
|  | # Disable default dynamic types for testing purposes | 
|  | disabledynamics() | 
|  |  | 
|  | # Install the control-c handler. | 
|  | unittest2.signals.installHandler() | 
|  |  | 
|  | lldbutil.mkdir_p(configuration.sdir_name) | 
|  | os.environ["LLDB_SESSION_DIRNAME"] = configuration.sdir_name | 
|  |  | 
|  | sys.stderr.write( | 
|  | "\nSession logs for test failures/errors/unexpected successes" | 
|  | " will go into directory '%s'\n" % | 
|  | configuration.sdir_name) | 
|  | sys.stderr.write("Command invoked: %s\n" % get_dotest_invocation()) | 
|  |  | 
|  | # | 
|  | # Invoke the default TextTestRunner to run the test suite | 
|  | # | 
|  | checkCompiler() | 
|  |  | 
|  | if configuration.verbose: | 
|  | print("compiler=%s" % configuration.compiler) | 
|  |  | 
|  | # Iterating over all possible architecture and compiler combinations. | 
|  | os.environ["ARCH"] = configuration.arch | 
|  | os.environ["CC"] = configuration.compiler | 
|  | configString = "arch=%s compiler=%s" % (configuration.arch, | 
|  | configuration.compiler) | 
|  |  | 
|  | # Output the configuration. | 
|  | if configuration.verbose: | 
|  | sys.stderr.write("\nConfiguration: " + configString + "\n") | 
|  |  | 
|  | # First, write out the number of collected test cases. | 
|  | if configuration.verbose: | 
|  | sys.stderr.write(configuration.separator + "\n") | 
|  | sys.stderr.write( | 
|  | "Collected %d test%s\n\n" % | 
|  | (configuration.suite.countTestCases(), | 
|  | configuration.suite.countTestCases() != 1 and "s" or "")) | 
|  |  | 
|  | # Invoke the test runner. | 
|  | if configuration.count == 1: | 
|  | result = unittest2.TextTestRunner( | 
|  | stream=sys.stderr, | 
|  | verbosity=configuration.verbose, | 
|  | resultclass=test_result.LLDBTestResult).run( | 
|  | configuration.suite) | 
|  | else: | 
|  | # We are invoking the same test suite more than once.  In this case, | 
|  | # mark __ignore_singleton__ flag as True so the signleton pattern is | 
|  | # not enforced. | 
|  | test_result.LLDBTestResult.__ignore_singleton__ = True | 
|  | for i in range(configuration.count): | 
|  |  | 
|  | result = unittest2.TextTestRunner( | 
|  | stream=sys.stderr, | 
|  | verbosity=configuration.verbose, | 
|  | resultclass=test_result.LLDBTestResult).run( | 
|  | configuration.suite) | 
|  |  | 
|  | configuration.failed = not result.wasSuccessful() | 
|  |  | 
|  | if configuration.sdir_has_content and configuration.verbose: | 
|  | sys.stderr.write( | 
|  | "Session logs for test failures/errors/unexpected successes" | 
|  | " can be found in directory '%s'\n" % | 
|  | configuration.sdir_name) | 
|  |  | 
|  | if configuration.useCategories and len( | 
|  | configuration.failuresPerCategory) > 0: | 
|  | sys.stderr.write("Failures per category:\n") | 
|  | for category in configuration.failuresPerCategory: | 
|  | sys.stderr.write( | 
|  | "%s - %d\n" % | 
|  | (category, configuration.failuresPerCategory[category])) | 
|  |  | 
|  | # Exiting. | 
|  | exitTestSuite(configuration.failed) | 
|  |  | 
|  | if __name__ == "__main__": | 
|  | print( | 
|  | __file__ + | 
|  | " is for use as a module only.  It should not be run as a standalone script.") | 
|  | sys.exit(-1) |