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