1"""
2A simple testing framework for lldb using python's unit testing framework.
3
4Tests for lldb are written as python scripts which take advantage of the script
5bridging provided by LLDB.framework to interact with lldb core.
6
7A specific naming pattern is followed by the .py script to be recognized as
8a module which implements a test scenario, namely, Test*.py.
9
10To specify the directories where "Test*.py" python test scripts are located,
11you need to pass in a list of directory names.  By default, the current
12working directory is searched if nothing is specified on the command line.
13
14Type:
15
16./dotest.py -h
17
18for available options.
19"""
20
21from __future__ import absolute_import
22from __future__ import print_function
23
24# System modules
25import atexit
26import os
27import errno
28import logging
29import platform
30import re
31import signal
32import subprocess
33import sys
34
35# Third-party modules
36import six
37import unittest2
38
39# LLDB Modules
40import lldbsuite
41from . import configuration
42from . import dotest_args
43from . import lldbtest_config
44from . import test_categories
45from lldbsuite.test_event import formatter
46from . import test_result
47from lldbsuite.test_event.event_builder import EventBuilder
48from ..support import seven
49
50
51def is_exe(fpath):
52    """Returns true if fpath is an executable."""
53    if fpath == None:
54      return False
55    return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
56
57
58def which(program):
59    """Returns the full path to a program; None otherwise."""
60    fpath, _ = os.path.split(program)
61    if fpath:
62        if is_exe(program):
63            return program
64    else:
65        for path in os.environ["PATH"].split(os.pathsep):
66            exe_file = os.path.join(path, program)
67            if is_exe(exe_file):
68                return exe_file
69    return None
70
71
72def usage(parser):
73    parser.print_help()
74    if configuration.verbose > 0:
75        print("""
76Examples:
77
78This is an example of using the -f option to pinpoint to a specific test class
79and test method to be run:
80
81$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command
82----------------------------------------------------------------------
83Collected 1 test
84
85test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
86Test 'frame variable this' when stopped on a class constructor. ... ok
87
88----------------------------------------------------------------------
89Ran 1 test in 1.396s
90
91OK
92
93And this is an example of using the -p option to run a single file (the filename
94matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):
95
96$ ./dotest.py -v -p ObjC
97----------------------------------------------------------------------
98Collected 4 tests
99
100test_break_with_dsym (TestObjCMethods.FoundationTestCase)
101Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
102test_break_with_dwarf (TestObjCMethods.FoundationTestCase)
103Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
104test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)
105Lookup objective-c data types and evaluate expressions. ... ok
106test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)
107Lookup objective-c data types and evaluate expressions. ... ok
108
109----------------------------------------------------------------------
110Ran 4 tests in 16.661s
111
112OK
113
114Running of this script also sets up the LLDB_TEST environment variable so that
115individual test cases can locate their supporting files correctly.  The script
116tries to set up Python's search paths for modules by looking at the build tree
117relative to this script.  See also the '-i' option in the following example.
118
119Finally, this is an example of using the lldb.py module distributed/installed by
120Xcode4 to run against the tests under the 'forward' directory, and with the '-w'
121option to add some delay between two tests.  It uses ARCH=x86_64 to specify that
122as the architecture and CC=clang to specify the compiler used for the test run:
123
124$ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward
125
126Session logs for test failures/errors will go into directory '2010-11-11-13_56_16'
127----------------------------------------------------------------------
128Collected 2 tests
129
130test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
131Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
132test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
133Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
134
135----------------------------------------------------------------------
136Ran 2 tests in 5.659s
137
138OK
139
140The 'Session ...' verbiage is recently introduced (see also the '-s' option) to
141notify the directory containing the session logs for test failures or errors.
142In case there is any test failure/error, a similar message is appended at the
143end of the stderr output for your convenience.
144
145ENABLING LOGS FROM TESTS
146
147Option 1:
148
149Writing logs into different files per test case::
150
151This option is particularly useful when multiple dotest instances are created
152by dosep.py
153
154$ ./dotest.py --channel "lldb all"
155
156$ ./dotest.py --channel "lldb all" --channel "gdb-remote packets"
157
158These log files are written to:
159
160<session-dir>/<test-id>-host.log (logs from lldb host process)
161<session-dir>/<test-id>-server.log (logs from debugserver/lldb-server)
162<session-dir>/<test-id>-<test-result>.log (console logs)
163
164By default, logs from successful runs are deleted.  Use the --log-success flag
165to create reference logs for debugging.
166
167$ ./dotest.py --log-success
168
169Option 2: (DEPRECATED)
170
171The following options can only enable logs from the host lldb process.
172Only categories from the "lldb" or "gdb-remote" channels can be enabled
173They also do not automatically enable logs in locally running debug servers.
174Also, logs from all test case are written into each log file
175
176o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
177  with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
178
179o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
180  'process.gdb-remote' subsystem with a default option of 'packets' if
181  GDB_REMOTE_LOG_OPTION is not defined.
182
183""")
184    sys.exit(0)
185
186
187def parseExclusion(exclusion_file):
188    """Parse an exclusion file, of the following format, where
189       'skip files', 'skip methods', 'xfail files', and 'xfail methods'
190       are the possible list heading values:
191
192       skip files
193       <file name>
194       <file name>
195
196       xfail methods
197       <method name>
198    """
199    excl_type = None
200
201    with open(exclusion_file) as f:
202        for line in f:
203            line = line.strip()
204            if not excl_type:
205                excl_type = line
206                continue
207
208            if not line:
209                excl_type = None
210            elif excl_type == 'skip':
211                if not configuration.skip_tests:
212                    configuration.skip_tests = []
213                configuration.skip_tests.append(line)
214            elif excl_type == 'xfail':
215                if not configuration.xfail_tests:
216                    configuration.xfail_tests = []
217                configuration.xfail_tests.append(line)
218
219
220def parseOptionsAndInitTestdirs():
221    """Initialize the list of directories containing our unittest scripts.
222
223    '-h/--help as the first option prints out usage info and exit the program.
224    """
225
226    do_help = False
227
228    platform_system = platform.system()
229    platform_machine = platform.machine()
230
231    parser = dotest_args.create_parser()
232    args = dotest_args.parse_args(parser, sys.argv[1:])
233
234    if args.unset_env_varnames:
235        for env_var in args.unset_env_varnames:
236            if env_var in os.environ:
237                # From Python Doc: When unsetenv() is supported, deletion of items in os.environ
238                # is automatically translated into a corresponding call to
239                # unsetenv().
240                del os.environ[env_var]
241                # os.unsetenv(env_var)
242
243    if args.set_env_vars:
244        for env_var in args.set_env_vars:
245            parts = env_var.split('=', 1)
246            if len(parts) == 1:
247                os.environ[parts[0]] = ""
248            else:
249                os.environ[parts[0]] = parts[1]
250
251    if args.set_inferior_env_vars:
252        lldbtest_config.inferior_env = ' '.join(args.set_inferior_env_vars)
253
254    # only print the args if being verbose (and parsable is off)
255    if args.v and not args.q:
256        print(sys.argv)
257
258    if args.h:
259        do_help = True
260
261    if args.compiler:
262        configuration.compiler = os.path.realpath(args.compiler)
263        if not is_exe(configuration.compiler):
264            configuration.compiler = which(args.compiler)
265        if not is_exe(configuration.compiler):
266            logging.error(
267                    '%s is not a valid compiler executable; aborting...',
268                    args.compiler)
269            sys.exit(-1)
270    else:
271        # Use a compiler appropriate appropriate for the Apple SDK if one was
272        # specified
273        if platform_system == 'Darwin' and args.apple_sdk:
274            configuration.compiler = seven.get_command_output(
275                'xcrun -sdk "%s" -find clang 2> /dev/null' %
276                (args.apple_sdk))
277        else:
278            # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first
279            candidateCompilers = ['clang-3.5', 'clang', 'gcc']
280            for candidate in candidateCompilers:
281                if which(candidate):
282                    configuration.compiler = candidate
283                    break
284
285    if args.dsymutil:
286      os.environ['DSYMUTIL'] = args.dsymutil
287    elif platform_system == 'Darwin':
288      os.environ['DSYMUTIL'] = seven.get_command_output(
289          'xcrun -find -toolchain default dsymutil')
290
291    if args.filecheck:
292        # The lldb-dotest script produced by the CMake build passes in a path
293        # to a working FileCheck binary. So does one specific Xcode project
294        # target. However, when invoking dotest.py directly, a valid --filecheck
295        # option needs to be given.
296        configuration.filecheck = os.path.abspath(args.filecheck)
297    else:
298        outputPaths = get_llvm_bin_dirs()
299        for outputPath in outputPaths:
300            candidatePath = os.path.join(outputPath, 'FileCheck')
301            if is_exe(candidatePath):
302                configuration.filecheck = candidatePath
303                break
304
305    if not configuration.get_filecheck_path():
306        logging.warning('No valid FileCheck executable; some tests may fail...')
307        logging.warning('(Double-check the --filecheck argument to dotest.py)')
308
309    if args.channels:
310        lldbtest_config.channels = args.channels
311
312    if args.log_success:
313        lldbtest_config.log_success = args.log_success
314
315    if args.out_of_tree_debugserver:
316        lldbtest_config.out_of_tree_debugserver = args.out_of_tree_debugserver
317
318    # Set SDKROOT if we are using an Apple SDK
319    if platform_system == 'Darwin' and args.apple_sdk:
320        os.environ['SDKROOT'] = seven.get_command_output(
321            'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' %
322            (args.apple_sdk))
323
324    if args.arch:
325        configuration.arch = args.arch
326        if configuration.arch.startswith(
327                'arm') and platform_system == 'Darwin' and not args.apple_sdk:
328            os.environ['SDKROOT'] = seven.get_command_output(
329                'xcrun --sdk iphoneos.internal --show-sdk-path 2> /dev/null')
330            if not os.path.exists(os.environ['SDKROOT']):
331                os.environ['SDKROOT'] = seven.get_command_output(
332                    'xcrun --sdk iphoneos --show-sdk-path 2> /dev/null')
333    else:
334        configuration.arch = platform_machine
335
336    if args.categoriesList:
337        configuration.categoriesList = set(
338            test_categories.validate(
339                args.categoriesList, False))
340        configuration.useCategories = True
341    else:
342        configuration.categoriesList = []
343
344    if args.skipCategories:
345        configuration.skipCategories += test_categories.validate(
346            args.skipCategories, False)
347
348    if args.E:
349        cflags_extras = args.E
350        os.environ['CFLAGS_EXTRAS'] = cflags_extras
351
352    if args.d:
353        sys.stdout.write(
354            "Suspending the process %d to wait for debugger to attach...\n" %
355            os.getpid())
356        sys.stdout.flush()
357        os.kill(os.getpid(), signal.SIGSTOP)
358
359    if args.f:
360        if any([x.startswith('-') for x in args.f]):
361            usage(parser)
362        configuration.filters.extend(args.f)
363        # Shut off multiprocessing mode when additional filters are specified.
364        # The rational is that the user is probably going after a very specific
365        # test and doesn't need a bunch of parallel test runners all looking for
366        # it in a frenzy.  Also, '-v' now spits out all test run output even
367        # on success, so the standard recipe for redoing a failing test (with -v
368        # and a -f to filter to the specific test) now causes all test scanning
369        # (in parallel) to print results for do-nothing runs in a very distracting
370        # manner.  If we really need filtered parallel runs in the future, consider
371        # adding a --no-output-on-success that prevents -v from setting
372        # output-on-success.
373        configuration.no_multiprocess_test_runner = True
374
375    if args.l:
376        configuration.skip_long_running_test = False
377
378    if args.framework:
379        configuration.lldbFrameworkPath = args.framework
380
381    if args.executable:
382        # lldb executable is passed explicitly
383        lldbtest_config.lldbExec = os.path.realpath(args.executable)
384        if not is_exe(lldbtest_config.lldbExec):
385            lldbtest_config.lldbExec = which(args.executable)
386        if not is_exe(lldbtest_config.lldbExec):
387            logging.error(
388                    '%s is not a valid executable to test; aborting...',
389                    args.executable)
390            sys.exit(-1)
391
392    if args.server:
393        os.environ['LLDB_DEBUGSERVER_PATH'] = args.server
394
395    if args.excluded:
396        for excl_file in args.excluded:
397            parseExclusion(excl_file)
398
399    if args.p:
400        if args.p.startswith('-'):
401            usage(parser)
402        configuration.regexp = args.p
403
404    if args.q:
405        configuration.parsable = True
406
407    if args.s:
408        if args.s.startswith('-'):
409            usage(parser)
410        configuration.sdir_name = args.s
411    configuration.session_file_format = args.session_file_format
412
413    if args.t:
414        os.environ['LLDB_COMMAND_TRACE'] = 'YES'
415
416    if args.v:
417        configuration.verbose = 2
418
419    # argparse makes sure we have a number
420    if args.sharp:
421        configuration.count = args.sharp
422
423    if sys.platform.startswith('win32'):
424        os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str(
425            args.disable_crash_dialog)
426        os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True)
427
428    if do_help:
429        usage(parser)
430
431    if args.no_multiprocess:
432        configuration.no_multiprocess_test_runner = True
433
434    if args.inferior:
435        configuration.is_inferior_test_runner = True
436
437    if args.num_threads:
438        configuration.num_threads = args.num_threads
439
440    if args.test_subdir:
441        configuration.exclusive_test_subdir = args.test_subdir
442
443    if args.test_runner_name:
444        configuration.test_runner_name = args.test_runner_name
445
446    # Capture test results-related args.
447    if args.curses and not args.inferior:
448        # Act as if the following args were set.
449        args.results_formatter = "lldbsuite.test_event.formatter.curses.Curses"
450        args.results_file = "stdout"
451
452    if args.results_file:
453        configuration.results_filename = args.results_file
454
455    if args.results_port:
456        configuration.results_port = args.results_port
457
458    if args.results_file and args.results_port:
459        sys.stderr.write(
460            "only one of --results-file and --results-port should "
461            "be specified\n")
462        usage(args)
463
464    if args.results_formatter:
465        configuration.results_formatter_name = args.results_formatter
466    if args.results_formatter_options:
467        configuration.results_formatter_options = args.results_formatter_options
468
469    # Default to using the BasicResultsFormatter if no formatter is specified
470    # and we're not a test inferior.
471    if not args.inferior and configuration.results_formatter_name is None:
472        configuration.results_formatter_name = (
473            "lldbsuite.test_event.formatter.results_formatter.ResultsFormatter")
474
475    # rerun-related arguments
476    configuration.rerun_all_issues = args.rerun_all_issues
477    configuration.rerun_max_file_threshold = args.rerun_max_file_threshold
478
479    if args.lldb_platform_name:
480        configuration.lldb_platform_name = args.lldb_platform_name
481    if args.lldb_platform_url:
482        configuration.lldb_platform_url = args.lldb_platform_url
483    if args.lldb_platform_working_dir:
484        configuration.lldb_platform_working_dir = args.lldb_platform_working_dir
485    if args.test_build_dir:
486        configuration.test_build_dir = args.test_build_dir
487
488    if args.event_add_entries and len(args.event_add_entries) > 0:
489        entries = {}
490        # Parse out key=val pairs, separated by comma
491        for keyval in args.event_add_entries.split(","):
492            key_val_entry = keyval.split("=")
493            if len(key_val_entry) == 2:
494                (key, val) = key_val_entry
495                val_parts = val.split(':')
496                if len(val_parts) > 1:
497                    (val, val_type) = val_parts
498                    if val_type == 'int':
499                        val = int(val)
500                entries[key] = val
501        # Tell the event builder to create all events with these
502        # key/val pairs in them.
503        if len(entries) > 0:
504            EventBuilder.add_entries_to_all_events(entries)
505
506    # Gather all the dirs passed on the command line.
507    if len(args.args) > 0:
508        configuration.testdirs = [os.path.realpath(os.path.abspath(x)) for x in args.args]
509        # Shut off multiprocessing mode when test directories are specified.
510        configuration.no_multiprocess_test_runner = True
511
512    lldbtest_config.codesign_identity = args.codesign_identity
513
514    #print("testdirs:", testdirs)
515
516
517def getXcodeOutputPaths(lldbRootDirectory):
518    result = []
519
520    # These are for xcode build directories.
521    xcode3_build_dir = ['build']
522    xcode4_build_dir = ['build', 'lldb', 'Build', 'Products']
523
524    configurations = [
525        ['Debug'],
526        ['DebugClang'],
527        ['Release'],
528        ['BuildAndIntegration']]
529    xcode_build_dirs = [xcode3_build_dir, xcode4_build_dir]
530    for configuration in configurations:
531        for xcode_build_dir in xcode_build_dirs:
532            outputPath = os.path.join(
533                lldbRootDirectory, *(xcode_build_dir + configuration))
534            result.append(outputPath)
535
536    return result
537
538
539def setupTestResults():
540    """Sets up test results-related objects based on arg settings."""
541    # Setup the results formatter configuration.
542    formatter_config = formatter.FormatterConfig()
543    formatter_config.filename = configuration.results_filename
544    formatter_config.formatter_name = configuration.results_formatter_name
545    formatter_config.formatter_options = (
546        configuration.results_formatter_options)
547    formatter_config.port = configuration.results_port
548
549    # Create the results formatter.
550    formatter_spec = formatter.create_results_formatter(
551        formatter_config)
552    if formatter_spec is not None and formatter_spec.formatter is not None:
553        configuration.results_formatter_object = formatter_spec.formatter
554
555        # Send an initialize message to the formatter.
556        initialize_event = EventBuilder.bare_event("initialize")
557        if isMultiprocessTestRunner():
558            if (configuration.test_runner_name is not None and
559                    configuration.test_runner_name == "serial"):
560                # Only one worker queue here.
561                worker_count = 1
562            else:
563                # Workers will be the number of threads specified.
564                worker_count = configuration.num_threads
565        else:
566            worker_count = 1
567        initialize_event["worker_count"] = worker_count
568
569        formatter_spec.formatter.handle_event(initialize_event)
570
571        # Make sure we clean up the formatter on shutdown.
572        if formatter_spec.cleanup_func is not None:
573            atexit.register(formatter_spec.cleanup_func)
574
575
576def getOutputPaths(lldbRootDirectory):
577    """
578    Returns typical build output paths for the lldb executable
579
580    lldbDirectory - path to the root of the lldb svn/git repo
581    """
582    result = []
583
584    if sys.platform == 'darwin':
585        result.extend(getXcodeOutputPaths(lldbRootDirectory))
586
587    # cmake builds?  look for build or build/host folder next to llvm directory
588    # lldb is located in llvm/tools/lldb so we need to go up three levels
589    llvmParentDir = os.path.abspath(
590        os.path.join(
591            lldbRootDirectory,
592            os.pardir,
593            os.pardir,
594            os.pardir))
595    result.append(os.path.join(llvmParentDir, 'build', 'bin'))
596    result.append(os.path.join(llvmParentDir, 'build', 'host', 'bin'))
597
598    # some cmake developers keep their build directory beside their lldb
599    # directory
600    lldbParentDir = os.path.abspath(os.path.join(lldbRootDirectory, os.pardir))
601    result.append(os.path.join(lldbParentDir, 'build', 'bin'))
602    result.append(os.path.join(lldbParentDir, 'build', 'host', 'bin'))
603
604    return result
605
606def get_llvm_bin_dirs():
607    """
608    Returns an array of paths that may have the llvm/clang/etc binaries
609    in them, relative to this current file.
610    Returns an empty array if none are found.
611    """
612    result = []
613
614    lldb_root_path = os.path.join(
615        os.path.dirname(__file__), "..", "..", "..", "..")
616    paths_to_try = [
617        "llvm-build/Release+Asserts/x86_64/bin",
618        "llvm-build/Debug+Asserts/x86_64/bin",
619        "llvm-build/Release/x86_64/bin",
620        "llvm-build/Debug/x86_64/bin",
621        "llvm-build/Ninja-DebugAssert/llvm-macosx-x86_64/bin",
622        "llvm-build/Ninja-DebugAssert+asan/llvm-macosx-x86_64/bin",
623        "llvm-build/Ninja-ReleaseAssert/llvm-macosx-x86_64/bin",
624        "llvm-build/Ninja-ReleaseAssert+asan/llvm-macosx-x86_64/bin",
625        "llvm-build/Ninja-RelWithDebInfoAssert/llvm-macosx-x86_64/bin",
626        "llvm-build/Ninja-RelWithDebInfoAssert+asan/llvm-macosx-x86_64/bin",
627    ]
628    for p in paths_to_try:
629        path = os.path.join(lldb_root_path, p)
630        if os.path.exists(path):
631            result.append(path)
632
633    return result
634
635def setupSysPath():
636    """
637    Add LLDB.framework/Resources/Python to the search paths for modules.
638    As a side effect, we also discover the 'lldb' executable and export it here.
639    """
640
641    # Get the directory containing the current script.
642    if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ:
643        scriptPath = os.environ["DOTEST_SCRIPT_DIR"]
644    else:
645        scriptPath = os.path.dirname(os.path.realpath(__file__))
646    if not scriptPath.endswith('test'):
647        print("This script expects to reside in lldb's test directory.")
648        sys.exit(-1)
649
650    os.environ["LLDB_TEST"] = scriptPath
651
652    # Set up the root build directory.
653    builddir = configuration.test_build_dir
654    if not configuration.test_build_dir:
655        raise Exception("test_build_dir is not set")
656    os.environ["LLDB_BUILD"] = os.path.abspath(configuration.test_build_dir)
657
658    # Set up the LLDB_SRC environment variable, so that the tests can locate
659    # the LLDB source code.
660    os.environ["LLDB_SRC"] = lldbsuite.lldb_root
661
662    pluginPath = os.path.join(scriptPath, 'plugins')
663    toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode')
664    toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server')
665
666    # Insert script dir, plugin dir and lldb-server dir to the sys.path.
667    sys.path.insert(0, pluginPath)
668    # Adding test/tools/lldb-vscode to the path makes it easy to
669    # "import lldb_vscode_testcase" from the VSCode tests
670    sys.path.insert(0, toolsLLDBVSCode)
671    # Adding test/tools/lldb-server to the path makes it easy
672    sys.path.insert(0, toolsLLDBServerPath)
673    # to "import lldbgdbserverutils" from the lldb-server tests
674
675    # This is the root of the lldb git/svn checkout
676    # When this changes over to a package instead of a standalone script, this
677    # will be `lldbsuite.lldb_root`
678    lldbRootDirectory = lldbsuite.lldb_root
679
680    # Some of the tests can invoke the 'lldb' command directly.
681    # We'll try to locate the appropriate executable right here.
682
683    # The lldb executable can be set from the command line
684    # if it's not set, we try to find it now
685    # first, we try the environment
686    if not lldbtest_config.lldbExec:
687        # First, you can define an environment variable LLDB_EXEC specifying the
688        # full pathname of the lldb executable.
689        if "LLDB_EXEC" in os.environ:
690            lldbtest_config.lldbExec = os.environ["LLDB_EXEC"]
691
692    if not lldbtest_config.lldbExec:
693        outputPaths = getOutputPaths(lldbRootDirectory)
694        for outputPath in outputPaths:
695            candidatePath = os.path.join(outputPath, 'lldb')
696            if is_exe(candidatePath):
697                lldbtest_config.lldbExec = candidatePath
698                break
699
700    if not lldbtest_config.lldbExec:
701        # Last, check the path
702        lldbtest_config.lldbExec = which('lldb')
703
704    if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec):
705        print(
706            "'{}' is not a path to a valid executable".format(
707                lldbtest_config.lldbExec))
708        lldbtest_config.lldbExec = None
709
710    if not lldbtest_config.lldbExec:
711        print("The 'lldb' executable cannot be located.  Some of the tests may not be run as a result.")
712        sys.exit(-1)
713
714    # confusingly, this is the "bin" directory
715    lldbLibDir = os.path.dirname(lldbtest_config.lldbExec)
716    os.environ["LLDB_LIB_DIR"] = lldbLibDir
717    lldbImpLibDir = os.path.join(
718        lldbLibDir,
719        '..',
720        'lib') if sys.platform.startswith('win32') else lldbLibDir
721    os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir
722    print("LLDB library dir:", os.environ["LLDB_LIB_DIR"])
723    print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"])
724    os.system('%s -v' % lldbtest_config.lldbExec)
725
726    lldbDir = os.path.dirname(lldbtest_config.lldbExec)
727
728    lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode")
729    if is_exe(lldbVSCodeExec):
730        os.environ["LLDBVSCODE_EXEC"] = lldbVSCodeExec
731    else:
732        if not configuration.shouldSkipBecauseOfCategories(["lldb-vscode"]):
733            print(
734                "The 'lldb-vscode' executable cannot be located.  The lldb-vscode tests can not be run as a result.")
735            configuration.skipCategories.append("lldb-vscode")
736
737    lldbPythonDir = None  # The directory that contains 'lldb/__init__.py'
738    if not configuration.lldbFrameworkPath and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")):
739        configuration.lldbFrameworkPath = os.path.join(lldbLibDir, "LLDB.framework")
740    if configuration.lldbFrameworkPath:
741        lldbtest_config.lldbFrameworkPath = configuration.lldbFrameworkPath
742        candidatePath = os.path.join(
743            configuration.lldbFrameworkPath, 'Resources', 'Python')
744        if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')):
745            lldbPythonDir = candidatePath
746        if not lldbPythonDir:
747            print(
748                'Resources/Python/lldb/__init__.py was not found in ' +
749                configuration.lldbFrameworkPath)
750            sys.exit(-1)
751    else:
752        # If our lldb supports the -P option, use it to find the python path:
753        init_in_python_dir = os.path.join('lldb', '__init__.py')
754
755        lldb_dash_p_result = subprocess.check_output(
756            [lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True)
757
758        if lldb_dash_p_result and not lldb_dash_p_result.startswith(
759                ("<", "lldb: invalid option:")) and not lldb_dash_p_result.startswith("Traceback"):
760            lines = lldb_dash_p_result.splitlines()
761
762            # Workaround for readline vs libedit issue on FreeBSD.  If stdout
763            # is not a terminal Python executes
764            #     rl_variable_bind ("enable-meta-key", "off");
765            # This produces a warning with FreeBSD's libedit because the
766            # enable-meta-key variable is unknown.  Not an issue on Apple
767            # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__
768            # around the call.  See http://bugs.python.org/issue19884 for more
769            # information.  For now we just discard the warning output.
770            if len(lines) >= 1 and lines[0].startswith(
771                    "bind: Invalid command"):
772                lines.pop(0)
773
774            # Taking the last line because lldb outputs
775            # 'Cannot read termcap database;\nusing dumb terminal settings.\n'
776            # before the path
777            if len(lines) >= 1 and os.path.isfile(
778                    os.path.join(lines[-1], init_in_python_dir)):
779                lldbPythonDir = lines[-1]
780                if "freebsd" in sys.platform or "linux" in sys.platform:
781                    os.environ['LLDB_LIB_DIR'] = os.path.join(
782                        lldbPythonDir, '..', '..')
783
784        if not lldbPythonDir:
785            if platform.system() == "Darwin":
786                python_resource_dir = ['LLDB.framework', 'Resources', 'Python']
787                outputPaths = getXcodeOutputPaths(lldbRootDirectory)
788                for outputPath in outputPaths:
789                    candidatePath = os.path.join(
790                        outputPath, *python_resource_dir)
791                    if os.path.isfile(
792                        os.path.join(
793                            candidatePath,
794                            init_in_python_dir)):
795                        lldbPythonDir = candidatePath
796                        break
797
798                if not lldbPythonDir:
799                    print("lldb.py is not found, some tests may fail.")
800            else:
801                print(
802                    "Unable to load lldb extension module.  Possible reasons for this include:")
803                print("  1) LLDB was built with LLDB_DISABLE_PYTHON=1")
804                print(
805                    "  2) PYTHONPATH and PYTHONHOME are not set correctly.  PYTHONHOME should refer to")
806                print(
807                    "     the version of Python that LLDB built and linked against, and PYTHONPATH")
808                print(
809                    "     should contain the Lib directory for the same python distro, as well as the")
810                print("     location of LLDB\'s site-packages folder.")
811                print(
812                    "  3) A different version of Python than that which was built against is exported in")
813                print("     the system\'s PATH environment variable, causing conflicts.")
814                print(
815                    "  4) The executable '%s' could not be found.  Please check " %
816                    lldbtest_config.lldbExec)
817                print("     that it exists and is executable.")
818
819    if lldbPythonDir:
820        lldbPythonDir = os.path.normpath(lldbPythonDir)
821        # Some of the code that uses this path assumes it hasn't resolved the Versions... link.
822        # If the path we've constructed looks like that, then we'll strip out
823        # the Versions/A part.
824        (before, frameWithVersion, after) = lldbPythonDir.rpartition(
825            "LLDB.framework/Versions/A")
826        if frameWithVersion != "":
827            lldbPythonDir = before + "LLDB.framework" + after
828
829        lldbPythonDir = os.path.abspath(lldbPythonDir)
830
831        # If tests need to find LLDB_FRAMEWORK, now they can do it
832        os.environ["LLDB_FRAMEWORK"] = os.path.dirname(
833            os.path.dirname(lldbPythonDir))
834
835        # This is to locate the lldb.py module.  Insert it right after
836        # sys.path[0].
837        sys.path[1:1] = [lldbPythonDir]
838
839
840def visit_file(dir, name):
841    # Try to match the regexp pattern, if specified.
842    if configuration.regexp:
843        if not re.search(configuration.regexp, name):
844            # We didn't match the regex, we're done.
845            return
846
847    if configuration.skip_tests:
848        for file_regexp in configuration.skip_tests:
849            if re.search(file_regexp, name):
850                return
851
852    # We found a match for our test.  Add it to the suite.
853
854    # Update the sys.path first.
855    if not sys.path.count(dir):
856        sys.path.insert(0, dir)
857    base = os.path.splitext(name)[0]
858
859    # Thoroughly check the filterspec against the base module and admit
860    # the (base, filterspec) combination only when it makes sense.
861    filterspec = None
862    for filterspec in configuration.filters:
863        # Optimistically set the flag to True.
864        filtered = True
865        module = __import__(base)
866        parts = filterspec.split('.')
867        obj = module
868        for part in parts:
869            try:
870                parent, obj = obj, getattr(obj, part)
871            except AttributeError:
872                # The filterspec has failed.
873                filtered = False
874                break
875
876        # If filtered, we have a good filterspec.  Add it.
877        if filtered:
878            # print("adding filter spec %s to module %s" % (filterspec, module))
879            configuration.suite.addTests(
880                unittest2.defaultTestLoader.loadTestsFromName(
881                    filterspec, module))
882            continue
883
884    # Forgo this module if the (base, filterspec) combo is invalid
885    if configuration.filters and not filtered:
886        return
887
888    if not filterspec or not filtered:
889        # Add the entire file's worth of tests since we're not filtered.
890        # Also the fail-over case when the filterspec branch
891        # (base, filterspec) combo doesn't make sense.
892        configuration.suite.addTests(
893            unittest2.defaultTestLoader.loadTestsFromName(base))
894
895
896# TODO: This should be replaced with a call to find_test_files_in_dir_tree.
897def visit(prefix, dir, names):
898    """Visitor function for os.path.walk(path, visit, arg)."""
899
900    dir_components = set(dir.split(os.sep))
901    excluded_components = set(['.svn', '.git'])
902    if dir_components.intersection(excluded_components):
903        return
904
905    # Gather all the Python test file names that follow the Test*.py pattern.
906    python_test_files = [
907        name
908        for name in names
909        if name.endswith('.py') and name.startswith(prefix)]
910
911    # Visit all the python test files.
912    for name in python_test_files:
913        try:
914            # Ensure we error out if we have multiple tests with the same
915            # base name.
916            # Future improvement: find all the places where we work with base
917            # names and convert to full paths.  We have directory structure
918            # to disambiguate these, so we shouldn't need this constraint.
919            if name in configuration.all_tests:
920                raise Exception("Found multiple tests with the name %s" % name)
921            configuration.all_tests.add(name)
922
923            # Run the relevant tests in the python file.
924            visit_file(dir, name)
925        except Exception as ex:
926            # Convert this exception to a test event error for the file.
927            test_filename = os.path.abspath(os.path.join(dir, name))
928            if configuration.results_formatter_object is not None:
929                # Grab the backtrace for the exception.
930                import traceback
931                backtrace = traceback.format_exc()
932
933                # Generate the test event.
934                configuration.results_formatter_object.handle_event(
935                    EventBuilder.event_for_job_test_add_error(
936                        test_filename, ex, backtrace))
937            raise
938
939
940def disabledynamics():
941    import lldb
942    ci = lldb.DBG.GetCommandInterpreter()
943    res = lldb.SBCommandReturnObject()
944    ci.HandleCommand(
945        "setting set target.prefer-dynamic-value no-dynamic-values",
946        res,
947        False)
948    if not res.Succeeded():
949        raise Exception('disabling dynamic type support failed')
950
951
952def lldbLoggings():
953    import lldb
954    """Check and do lldb loggings if necessary."""
955
956    # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
957    # defined.  Use ${LLDB_LOG} to specify the log file.
958    ci = lldb.DBG.GetCommandInterpreter()
959    res = lldb.SBCommandReturnObject()
960    if ("LLDB_LOG" in os.environ):
961        open(os.environ["LLDB_LOG"], 'w').close()
962        if ("LLDB_LOG_OPTION" in os.environ):
963            lldb_log_option = os.environ["LLDB_LOG_OPTION"]
964        else:
965            lldb_log_option = "event process expr state api"
966        ci.HandleCommand(
967            "log enable -n -f " +
968            os.environ["LLDB_LOG"] +
969            " lldb " +
970            lldb_log_option,
971            res)
972        if not res.Succeeded():
973            raise Exception('log enable failed (check LLDB_LOG env variable)')
974
975    if ("LLDB_LINUX_LOG" in os.environ):
976        open(os.environ["LLDB_LINUX_LOG"], 'w').close()
977        if ("LLDB_LINUX_LOG_OPTION" in os.environ):
978            lldb_log_option = os.environ["LLDB_LINUX_LOG_OPTION"]
979        else:
980            lldb_log_option = "event process expr state api"
981        ci.HandleCommand(
982            "log enable -n -f " +
983            os.environ["LLDB_LINUX_LOG"] +
984            " linux " +
985            lldb_log_option,
986            res)
987        if not res.Succeeded():
988            raise Exception(
989                'log enable failed (check LLDB_LINUX_LOG env variable)')
990
991    # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
992    # Use ${GDB_REMOTE_LOG} to specify the log file.
993    if ("GDB_REMOTE_LOG" in os.environ):
994        if ("GDB_REMOTE_LOG_OPTION" in os.environ):
995            gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
996        else:
997            gdb_remote_log_option = "packets process"
998        ci.HandleCommand(
999            "log enable -n -f " + os.environ["GDB_REMOTE_LOG"] + " gdb-remote "
1000            + gdb_remote_log_option,
1001            res)
1002        if not res.Succeeded():
1003            raise Exception(
1004                'log enable failed (check GDB_REMOTE_LOG env variable)')
1005
1006
1007def getMyCommandLine():
1008    return ' '.join(sys.argv)
1009
1010# ======================================== #
1011#                                          #
1012# Execution of the test driver starts here #
1013#                                          #
1014# ======================================== #
1015
1016
1017def checkDsymForUUIDIsNotOn():
1018    cmd = ["defaults", "read", "com.apple.DebugSymbols"]
1019    process = subprocess.Popen(
1020        cmd,
1021        stdout=subprocess.PIPE,
1022        stderr=subprocess.STDOUT)
1023    cmd_output = process.stdout.read()
1024    output_str = cmd_output.decode("utf-8")
1025    if "DBGFileMappedPaths = " in output_str:
1026        print("%s =>" % ' '.join(cmd))
1027        print(output_str)
1028        print(
1029            "Disable automatic lookup and caching of dSYMs before running the test suite!")
1030        print("Exiting...")
1031        sys.exit(0)
1032
1033
1034def exitTestSuite(exitCode=None):
1035    import lldb
1036    lldb.SBDebugger.Terminate()
1037    if exitCode:
1038        sys.exit(exitCode)
1039
1040
1041def isMultiprocessTestRunner():
1042    # We're not multiprocess when we're either explicitly
1043    # the inferior (as specified by the multiprocess test
1044    # runner) OR we've been told to skip using the multiprocess
1045    # test runner
1046    return not (
1047        configuration.is_inferior_test_runner or configuration.no_multiprocess_test_runner)
1048
1049
1050def getVersionForSDK(sdk):
1051    sdk = str.lower(sdk)
1052    full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk)
1053    basename = os.path.basename(full_path)
1054    basename = os.path.splitext(basename)[0]
1055    basename = str.lower(basename)
1056    ver = basename.replace(sdk, '')
1057    return ver
1058
1059
1060def setDefaultTripleForPlatform():
1061    if configuration.lldb_platform_name == 'ios-simulator':
1062        triple_str = 'x86_64-apple-ios%s' % (
1063            getVersionForSDK('iphonesimulator'))
1064        os.environ['TRIPLE'] = triple_str
1065        return {'TRIPLE': triple_str}
1066    return {}
1067
1068
1069def checkCompiler():
1070    # Add some intervention here to sanity check that the compiler requested is sane.
1071    # If found not to be an executable program, we abort.
1072    c = configuration.compiler
1073    if which(c):
1074        return
1075
1076    if not sys.platform.startswith("darwin"):
1077        raise Exception(c + " is not a valid compiler")
1078
1079    pipe = subprocess.Popen(
1080        ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
1081    cmd_output = pipe.stdout.read()
1082    if not cmd_output or "not found" in cmd_output:
1083        raise Exception(c + " is not a valid compiler")
1084
1085    configuration.compiler = cmd_output.split('\n')[0]
1086    print("'xcrun -find %s' returning %s" % (c, configuration.compiler))
1087
1088def canRunLibcxxTests():
1089    from lldbsuite.test import lldbplatformutil
1090
1091    platform = lldbplatformutil.getPlatform()
1092
1093    if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin():
1094        return True, "libc++ always present"
1095
1096    if platform == "linux":
1097        if not os.path.isdir("/usr/include/c++/v1"):
1098            return False, "Unable to find libc++ installation"
1099        return True, "Headers found, let's hope they work"
1100
1101    return False, "Don't know how to build with libc++ on %s" % platform
1102
1103def checkLibcxxSupport():
1104    result, reason = canRunLibcxxTests()
1105    if result:
1106        return # libc++ supported
1107    if "libc++" in configuration.categoriesList:
1108        return # libc++ category explicitly requested, let it run.
1109    print("Libc++ tests will not be run because: " + reason)
1110    configuration.skipCategories.append("libc++")
1111
1112def canRunLibstdcxxTests():
1113    from lldbsuite.test import lldbplatformutil
1114
1115    platform = lldbplatformutil.getPlatform()
1116    if lldbplatformutil.target_is_android():
1117        platform = "android"
1118    if platform == "linux":
1119        return True, "libstdcxx always present"
1120    return False, "Don't know how to build with libstdcxx on %s" % platform
1121
1122def checkLibstdcxxSupport():
1123    result, reason = canRunLibstdcxxTests()
1124    if result:
1125        return # libstdcxx supported
1126    if "libstdcxx" in configuration.categoriesList:
1127        return # libstdcxx category explicitly requested, let it run.
1128    print("libstdcxx tests will not be run because: " + reason)
1129    configuration.skipCategories.append("libstdcxx")
1130
1131def canRunWatchpointTests():
1132    from lldbsuite.test import lldbplatformutil
1133
1134    platform = lldbplatformutil.getPlatform()
1135    if platform == "netbsd":
1136      if os.geteuid() == 0:
1137        return True, "root can always write dbregs"
1138      try:
1139        output = subprocess.check_output(["/sbin/sysctl", "-n",
1140          "security.models.extensions.user_set_dbregs"]).decode().strip()
1141        if output == "1":
1142          return True, "security.models.extensions.user_set_dbregs enabled"
1143      except subprocess.CalledProcessError:
1144        pass
1145      return False, "security.models.extensions.user_set_dbregs disabled"
1146    return True, "watchpoint support available"
1147
1148def checkWatchpointSupport():
1149    result, reason = canRunWatchpointTests()
1150    if result:
1151        return # watchpoints supported
1152    if "watchpoint" in configuration.categoriesList:
1153        return # watchpoint category explicitly requested, let it run.
1154    print("watchpoint tests will not be run because: " + reason)
1155    configuration.skipCategories.append("watchpoint")
1156
1157def checkDebugInfoSupport():
1158    import lldb
1159
1160    platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2]
1161    compiler = configuration.compiler
1162    skipped = []
1163    for cat in test_categories.debug_info_categories:
1164        if cat in configuration.categoriesList:
1165            continue # Category explicitly requested, let it run.
1166        if test_categories.is_supported_on_platform(cat, platform, compiler):
1167            continue
1168        configuration.skipCategories.append(cat)
1169        skipped.append(cat)
1170    if skipped:
1171        print("Skipping following debug info categories:", skipped)
1172
1173def run_suite():
1174    # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults
1175    # does not exist before proceeding to running the test suite.
1176    if sys.platform.startswith("darwin"):
1177        checkDsymForUUIDIsNotOn()
1178
1179    #
1180    # Start the actions by first parsing the options while setting up the test
1181    # directories, followed by setting up the search paths for lldb utilities;
1182    # then, we walk the directory trees and collect the tests into our test suite.
1183    #
1184    parseOptionsAndInitTestdirs()
1185
1186    # Setup test results (test results formatter and output handling).
1187    setupTestResults()
1188
1189    # If we are running as the multiprocess test runner, kick off the
1190    # multiprocess test runner here.
1191    if isMultiprocessTestRunner():
1192        from . import dosep
1193        dosep.main(
1194            configuration.num_threads,
1195            configuration.test_runner_name,
1196            configuration.results_formatter_object)
1197        raise Exception("should never get here")
1198    elif configuration.is_inferior_test_runner:
1199        # Shut off Ctrl-C processing in inferiors.  The parallel
1200        # test runner handles this more holistically.
1201        signal.signal(signal.SIGINT, signal.SIG_IGN)
1202
1203    setupSysPath()
1204
1205    #
1206    # If '-l' is specified, do not skip the long running tests.
1207    if not configuration.skip_long_running_test:
1208        os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
1209
1210    # For the time being, let's bracket the test runner within the
1211    # lldb.SBDebugger.Initialize()/Terminate() pair.
1212    import lldb
1213
1214    # Create a singleton SBDebugger in the lldb namespace.
1215    lldb.DBG = lldb.SBDebugger.Create()
1216
1217    if configuration.lldb_platform_name:
1218        print("Setting up remote platform '%s'" %
1219              (configuration.lldb_platform_name))
1220        lldb.remote_platform = lldb.SBPlatform(
1221            configuration.lldb_platform_name)
1222        if not lldb.remote_platform.IsValid():
1223            print(
1224                "error: unable to create the LLDB platform named '%s'." %
1225                (configuration.lldb_platform_name))
1226            exitTestSuite(1)
1227        if configuration.lldb_platform_url:
1228            # We must connect to a remote platform if a LLDB platform URL was
1229            # specified
1230            print(
1231                "Connecting to remote platform '%s' at '%s'..." %
1232                (configuration.lldb_platform_name, configuration.lldb_platform_url))
1233            platform_connect_options = lldb.SBPlatformConnectOptions(
1234                configuration.lldb_platform_url)
1235            err = lldb.remote_platform.ConnectRemote(platform_connect_options)
1236            if err.Success():
1237                print("Connected.")
1238            else:
1239                print("error: failed to connect to remote platform using URL '%s': %s" % (
1240                    configuration.lldb_platform_url, err))
1241                exitTestSuite(1)
1242        else:
1243            configuration.lldb_platform_url = None
1244
1245    platform_changes = setDefaultTripleForPlatform()
1246    first = True
1247    for key in platform_changes:
1248        if first:
1249            print("Environment variables setup for platform support:")
1250            first = False
1251        print("%s = %s" % (key, platform_changes[key]))
1252
1253    if configuration.lldb_platform_working_dir:
1254        print("Setting remote platform working directory to '%s'..." %
1255              (configuration.lldb_platform_working_dir))
1256        error = lldb.remote_platform.MakeDirectory(
1257            configuration.lldb_platform_working_dir, 448)  # 448 = 0o700
1258        if error.Fail():
1259            raise Exception("making remote directory '%s': %s" % (
1260                configuration.lldb_platform_working_dir, error))
1261
1262        if not lldb.remote_platform.SetWorkingDirectory(
1263                configuration.lldb_platform_working_dir):
1264            raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir)
1265        lldb.DBG.SetSelectedPlatform(lldb.remote_platform)
1266    else:
1267        lldb.remote_platform = None
1268        configuration.lldb_platform_working_dir = None
1269        configuration.lldb_platform_url = None
1270
1271    # Set up the working directory.
1272    # Note that it's not dotest's job to clean this directory.
1273    import lldbsuite.test.lldbutil as lldbutil
1274    build_dir = configuration.test_build_dir
1275    lldbutil.mkdir_p(build_dir)
1276
1277    target_platform = lldb.DBG.GetSelectedPlatform().GetTriple().split('-')[2]
1278
1279    checkLibcxxSupport()
1280    checkLibstdcxxSupport()
1281    checkWatchpointSupport()
1282    checkDebugInfoSupport()
1283
1284    # Don't do debugserver tests on anything except OS X.
1285    configuration.dont_do_debugserver_test = "linux" in target_platform or "freebsd" in target_platform or "windows" in target_platform
1286
1287    # Don't do lldb-server (llgs) tests on anything except Linux.
1288    configuration.dont_do_llgs_test = not ("linux" in target_platform)
1289
1290    # Collect tests from the specified testing directories. If a test
1291    # subdirectory filter is explicitly specified, limit the search to that
1292    # subdirectory.
1293    exclusive_test_subdir = configuration.get_absolute_path_to_exclusive_test_subdir()
1294    if exclusive_test_subdir:
1295        dirs_to_search = [exclusive_test_subdir]
1296    else:
1297        dirs_to_search = configuration.testdirs
1298    for testdir in dirs_to_search:
1299        for (dirpath, dirnames, filenames) in os.walk(testdir):
1300            visit('Test', dirpath, filenames)
1301
1302    #
1303    # Now that we have loaded all the test cases, run the whole test suite.
1304    #
1305
1306    # Turn on lldb loggings if necessary.
1307    lldbLoggings()
1308
1309    # Disable default dynamic types for testing purposes
1310    disabledynamics()
1311
1312    # Install the control-c handler.
1313    unittest2.signals.installHandler()
1314
1315    # If sdir_name is not specified through the '-s sdir_name' option, get a
1316    # timestamp string and export it as LLDB_SESSION_DIR environment var.  This will
1317    # be used when/if we want to dump the session info of individual test cases
1318    # later on.
1319    #
1320    # See also TestBase.dumpSessionInfo() in lldbtest.py.
1321    import datetime
1322    # The windows platforms don't like ':' in the pathname.
1323    timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
1324    if not configuration.sdir_name:
1325        configuration.sdir_name = timestamp_started
1326    os.environ["LLDB_SESSION_DIRNAME"] = os.path.join(
1327        os.getcwd(), configuration.sdir_name)
1328
1329    sys.stderr.write(
1330        "\nSession logs for test failures/errors/unexpected successes"
1331        " will go into directory '%s'\n" %
1332        configuration.sdir_name)
1333    sys.stderr.write("Command invoked: %s\n" % getMyCommandLine())
1334
1335    if not os.path.isdir(configuration.sdir_name):
1336        try:
1337            os.mkdir(configuration.sdir_name)
1338        except OSError as exception:
1339            if exception.errno != errno.EEXIST:
1340                raise
1341
1342    #
1343    # Invoke the default TextTestRunner to run the test suite
1344    #
1345    checkCompiler()
1346
1347    if not configuration.parsable:
1348        print("compiler=%s" % configuration.compiler)
1349
1350    # Iterating over all possible architecture and compiler combinations.
1351    os.environ["ARCH"] = configuration.arch
1352    os.environ["CC"] = configuration.compiler
1353    configString = "arch=%s compiler=%s" % (configuration.arch,
1354                                            configuration.compiler)
1355
1356    # Translate ' ' to '-' for pathname component.
1357    if six.PY2:
1358        import string
1359        tbl = string.maketrans(' ', '-')
1360    else:
1361        tbl = str.maketrans(' ', '-')
1362    configPostfix = configString.translate(tbl)
1363
1364    # Output the configuration.
1365    if not configuration.parsable:
1366        sys.stderr.write("\nConfiguration: " + configString + "\n")
1367
1368    # First, write out the number of collected test cases.
1369    if not configuration.parsable:
1370        sys.stderr.write(configuration.separator + "\n")
1371        sys.stderr.write(
1372            "Collected %d test%s\n\n" %
1373            (configuration.suite.countTestCases(),
1374             configuration.suite.countTestCases() != 1 and "s" or ""))
1375
1376    if configuration.parsable:
1377        v = 0
1378    else:
1379        v = configuration.verbose
1380
1381    # Invoke the test runner.
1382    if configuration.count == 1:
1383        result = unittest2.TextTestRunner(
1384            stream=sys.stderr,
1385            verbosity=v,
1386            resultclass=test_result.LLDBTestResult).run(
1387            configuration.suite)
1388    else:
1389        # We are invoking the same test suite more than once.  In this case,
1390        # mark __ignore_singleton__ flag as True so the signleton pattern is
1391        # not enforced.
1392        test_result.LLDBTestResult.__ignore_singleton__ = True
1393        for i in range(configuration.count):
1394
1395            result = unittest2.TextTestRunner(
1396                stream=sys.stderr,
1397                verbosity=v,
1398                resultclass=test_result.LLDBTestResult).run(
1399                configuration.suite)
1400
1401    configuration.failed = not result.wasSuccessful()
1402
1403    if configuration.sdir_has_content and not configuration.parsable:
1404        sys.stderr.write(
1405            "Session logs for test failures/errors/unexpected successes"
1406            " can be found in directory '%s'\n" %
1407            configuration.sdir_name)
1408
1409    if configuration.useCategories and len(
1410            configuration.failuresPerCategory) > 0:
1411        sys.stderr.write("Failures per category:\n")
1412        for category in configuration.failuresPerCategory:
1413            sys.stderr.write(
1414                "%s - %d\n" %
1415                (category, configuration.failuresPerCategory[category]))
1416
1417    # Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
1418    # This should not be necessary now.
1419    if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
1420        print("Terminating Test suite...")
1421        subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
1422
1423    # Exiting.
1424    exitTestSuite(configuration.failed)
1425
1426if __name__ == "__main__":
1427    print(
1428        __file__ +
1429        " is for use as a module only.  It should not be run as a standalone script.")
1430    sys.exit(-1)
1431