[lldb/Test] Fix missing yaml2obj in Xcode standalone build.
[lldb.git] / lldb / packages / Python / lldbsuite / test / dotest.py
1 """
2 A simple testing framework for lldb using python's unit testing framework.
3
4 Tests for lldb are written as python scripts which take advantage of the script
5 bridging provided by LLDB.framework to interact with lldb core.
6
7 A specific naming pattern is followed by the .py script to be recognized as
8 a module which implements a test scenario, namely, Test*.py.
9
10 To specify the directories where "Test*.py" python test scripts are located,
11 you need to pass in a list of directory names.  By default, the current
12 working directory is searched if nothing is specified on the command line.
13
14 Type:
15
16 ./dotest.py -h
17
18 for available options.
19 """
20
21 from __future__ import absolute_import
22 from __future__ import print_function
23
24 # System modules
25 import atexit
26 import datetime
27 import errno
28 import logging
29 import os
30 import platform
31 import re
32 import signal
33 import subprocess
34 import sys
35 import tempfile
36
37 # Third-party modules
38 import six
39 import unittest2
40
41 # LLDB Modules
42 import lldbsuite
43 from . import configuration
44 from . import dotest_args
45 from . import lldbtest_config
46 from . import test_categories
47 from lldbsuite.test_event import formatter
48 from . import test_result
49 from lldbsuite.test_event.event_builder import EventBuilder
50 from ..support import seven
51
52
53 def is_exe(fpath):
54     """Returns true if fpath is an executable."""
55     if fpath == None:
56         return False
57     return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
58
59
60 def which(program):
61     """Returns the full path to a program; None otherwise."""
62     fpath, _ = os.path.split(program)
63     if fpath:
64         if is_exe(program):
65             return program
66     else:
67         for path in os.environ["PATH"].split(os.pathsep):
68             exe_file = os.path.join(path, program)
69             if is_exe(exe_file):
70                 return exe_file
71     return None
72
73
74 def usage(parser):
75     parser.print_help()
76     if configuration.verbose > 0:
77         print("""
78 Examples:
79
80 This is an example of using the -f option to pinpoint to a specific test class
81 and test method to be run:
82
83 $ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command
84 ----------------------------------------------------------------------
85 Collected 1 test
86
87 test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
88 Test 'frame variable this' when stopped on a class constructor. ... ok
89
90 ----------------------------------------------------------------------
91 Ran 1 test in 1.396s
92
93 OK
94
95 And this is an example of using the -p option to run a single file (the filename
96 matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):
97
98 $ ./dotest.py -v -p ObjC
99 ----------------------------------------------------------------------
100 Collected 4 tests
101
102 test_break_with_dsym (TestObjCMethods.FoundationTestCase)
103 Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
104 test_break_with_dwarf (TestObjCMethods.FoundationTestCase)
105 Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok
106 test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)
107 Lookup objective-c data types and evaluate expressions. ... ok
108 test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)
109 Lookup objective-c data types and evaluate expressions. ... ok
110
111 ----------------------------------------------------------------------
112 Ran 4 tests in 16.661s
113
114 OK
115
116 Running of this script also sets up the LLDB_TEST environment variable so that
117 individual test cases can locate their supporting files correctly.  The script
118 tries to set up Python's search paths for modules by looking at the build tree
119 relative to this script.  See also the '-i' option in the following example.
120
121 Finally, this is an example of using the lldb.py module distributed/installed by
122 Xcode4 to run against the tests under the 'forward' directory, and with the '-w'
123 option to add some delay between two tests.  It uses ARCH=x86_64 to specify that
124 as the architecture and CC=clang to specify the compiler used for the test run:
125
126 $ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward
127
128 Session logs for test failures/errors will go into directory '2010-11-11-13_56_16'
129 ----------------------------------------------------------------------
130 Collected 2 tests
131
132 test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
133 Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
134 test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
135 Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
136
137 ----------------------------------------------------------------------
138 Ran 2 tests in 5.659s
139
140 OK
141
142 The 'Session ...' verbiage is recently introduced (see also the '-s' option) to
143 notify the directory containing the session logs for test failures or errors.
144 In case there is any test failure/error, a similar message is appended at the
145 end of the stderr output for your convenience.
146
147 ENABLING LOGS FROM TESTS
148
149 Option 1:
150
151 Writing logs into different files per test case::
152
153 $ ./dotest.py --channel "lldb all"
154
155 $ ./dotest.py --channel "lldb all" --channel "gdb-remote packets"
156
157 These log files are written to:
158
159 <session-dir>/<test-id>-host.log (logs from lldb host process)
160 <session-dir>/<test-id>-server.log (logs from debugserver/lldb-server)
161 <session-dir>/<test-id>-<test-result>.log (console logs)
162
163 By default, logs from successful runs are deleted.  Use the --log-success flag
164 to create reference logs for debugging.
165
166 $ ./dotest.py --log-success
167
168 """)
169     sys.exit(0)
170
171
172 def parseExclusion(exclusion_file):
173     """Parse an exclusion file, of the following format, where
174        'skip files', 'skip methods', 'xfail files', and 'xfail methods'
175        are the possible list heading values:
176
177        skip files
178        <file name>
179        <file name>
180
181        xfail methods
182        <method name>
183     """
184     excl_type = None
185
186     with open(exclusion_file) as f:
187         for line in f:
188             line = line.strip()
189             if not excl_type:
190                 excl_type = line
191                 continue
192
193             if not line:
194                 excl_type = None
195             elif excl_type == 'skip':
196                 if not configuration.skip_tests:
197                     configuration.skip_tests = []
198                 configuration.skip_tests.append(line)
199             elif excl_type == 'xfail':
200                 if not configuration.xfail_tests:
201                     configuration.xfail_tests = []
202                 configuration.xfail_tests.append(line)
203
204
205 def parseOptionsAndInitTestdirs():
206     """Initialize the list of directories containing our unittest scripts.
207
208     '-h/--help as the first option prints out usage info and exit the program.
209     """
210
211     do_help = False
212
213     platform_system = platform.system()
214     platform_machine = platform.machine()
215
216     try:
217         parser = dotest_args.create_parser()
218         args = parser.parse_args()
219     except:
220         raise
221
222     if args.unset_env_varnames:
223         for env_var in args.unset_env_varnames:
224             if env_var in os.environ:
225                 # From Python Doc: When unsetenv() is supported, deletion of items in os.environ
226                 # is automatically translated into a corresponding call to
227                 # unsetenv().
228                 del os.environ[env_var]
229                 # os.unsetenv(env_var)
230
231     if args.set_env_vars:
232         for env_var in args.set_env_vars:
233             parts = env_var.split('=', 1)
234             if len(parts) == 1:
235                 os.environ[parts[0]] = ""
236             else:
237                 os.environ[parts[0]] = parts[1]
238
239     if args.set_inferior_env_vars:
240         lldbtest_config.inferior_env = ' '.join(args.set_inferior_env_vars)
241
242     if args.h:
243         do_help = True
244
245     if args.compiler:
246         configuration.compiler = os.path.realpath(args.compiler)
247         if not is_exe(configuration.compiler):
248             configuration.compiler = which(args.compiler)
249         if not is_exe(configuration.compiler):
250             logging.error(
251                     '%s is not a valid compiler executable; aborting...',
252                     args.compiler)
253             sys.exit(-1)
254     else:
255         # Use a compiler appropriate appropriate for the Apple SDK if one was
256         # specified
257         if platform_system == 'Darwin' and args.apple_sdk:
258             configuration.compiler = seven.get_command_output(
259                 'xcrun -sdk "%s" -find clang 2> /dev/null' %
260                 (args.apple_sdk))
261         else:
262             # 'clang' on ubuntu 14.04 is 3.4 so we try clang-3.5 first
263             candidateCompilers = ['clang-3.5', 'clang', 'gcc']
264             for candidate in candidateCompilers:
265                 if which(candidate):
266                     configuration.compiler = candidate
267                     break
268
269     if args.dsymutil:
270         configuration.dsymutil = args.dsymutil
271     elif platform_system == 'Darwin':
272         configuration.dsymutil = seven.get_command_output(
273             'xcrun -find -toolchain default dsymutil')
274
275
276     # The lldb-dotest script produced by the CMake build passes in a path to a
277     # working FileCheck and yaml2obj binary. So does one specific Xcode
278     # project target. However, when invoking dotest.py directly, a valid
279     # --filecheck and --yaml2obj option needs to be given.
280     if args.filecheck:
281         configuration.filecheck = os.path.abspath(args.filecheck)
282
283     if args.yaml2obj:
284         configuration.yaml2obj = os.path.abspath(args.yaml2obj)
285
286     if not configuration.get_filecheck_path():
287         logging.warning('No valid FileCheck executable; some tests may fail...')
288         logging.warning('(Double-check the --filecheck argument to dotest.py)')
289
290     if args.channels:
291         lldbtest_config.channels = args.channels
292
293     if args.log_success:
294         lldbtest_config.log_success = args.log_success
295
296     if args.out_of_tree_debugserver:
297         lldbtest_config.out_of_tree_debugserver = args.out_of_tree_debugserver
298
299     # Set SDKROOT if we are using an Apple SDK
300     if platform_system == 'Darwin' and args.apple_sdk:
301         configuration.sdkroot = seven.get_command_output(
302             'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' %
303             (args.apple_sdk))
304
305     if args.arch:
306         configuration.arch = args.arch
307     else:
308         configuration.arch = platform_machine
309
310     if args.categories_list:
311         configuration.categories_list = set(
312             test_categories.validate(
313                 args.categories_list, False))
314         configuration.use_categories = True
315     else:
316         configuration.categories_list = []
317
318     if args.skip_categories:
319         configuration.skip_categories += test_categories.validate(
320             args.skip_categories, False)
321
322     if args.xfail_categories:
323         configuration.xfail_categories += test_categories.validate(
324             args.xfail_categories, False)
325
326     if args.E:
327         os.environ['CFLAGS_EXTRAS'] = args.E
328
329     if args.dwarf_version:
330         configuration.dwarf_version = args.dwarf_version
331         # We cannot modify CFLAGS_EXTRAS because they're used in test cases
332         # that explicitly require no debug info.
333         os.environ['CFLAGS'] = '-gdwarf-{}'.format(configuration.dwarf_version)
334
335     if args.settings:
336         for setting in args.settings:
337             if not len(setting) == 1 or not setting[0].count('='):
338                 logging.error('"%s" is not a setting in the form "key=value"',
339                               setting[0])
340                 sys.exit(-1)
341             setting_list = setting[0].split('=', 1)
342             configuration.settings.append((setting_list[0], setting_list[1]))
343
344     if args.d:
345         sys.stdout.write(
346             "Suspending the process %d to wait for debugger to attach...\n" %
347             os.getpid())
348         sys.stdout.flush()
349         os.kill(os.getpid(), signal.SIGSTOP)
350
351     if args.f:
352         if any([x.startswith('-') for x in args.f]):
353             usage(parser)
354         configuration.filters.extend(args.f)
355
356     if args.framework:
357         configuration.lldb_framework_path = args.framework
358
359     if args.executable:
360         # lldb executable is passed explicitly
361         lldbtest_config.lldbExec = os.path.realpath(args.executable)
362         if not is_exe(lldbtest_config.lldbExec):
363             lldbtest_config.lldbExec = which(args.executable)
364         if not is_exe(lldbtest_config.lldbExec):
365             logging.error(
366                     '%s is not a valid executable to test; aborting...',
367                     args.executable)
368             sys.exit(-1)
369
370     if args.server and args.out_of_tree_debugserver:
371         logging.warning('Both --server and --out-of-tree-debugserver are set')
372
373     if args.server and not args.out_of_tree_debugserver:
374         os.environ['LLDB_DEBUGSERVER_PATH'] = args.server
375
376     if args.excluded:
377         for excl_file in args.excluded:
378             parseExclusion(excl_file)
379
380     if args.p:
381         if args.p.startswith('-'):
382             usage(parser)
383         configuration.regexp = args.p
384
385     if args.s:
386         configuration.sdir_name = args.s
387     else:
388         timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
389         configuration.sdir_name = os.path.join(os.getcwd(), timestamp_started)
390
391     configuration.session_file_format = args.session_file_format
392
393     if args.t:
394         os.environ['LLDB_COMMAND_TRACE'] = 'YES'
395
396     if args.v:
397         configuration.verbose = 2
398
399     # argparse makes sure we have a number
400     if args.sharp:
401         configuration.count = args.sharp
402
403     if sys.platform.startswith('win32'):
404         os.environ['LLDB_DISABLE_CRASH_DIALOG'] = str(
405             args.disable_crash_dialog)
406         os.environ['LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE'] = str(True)
407
408     if do_help:
409         usage(parser)
410
411     if args.results_file:
412         configuration.results_filename = args.results_file
413
414     if args.results_formatter:
415         configuration.results_formatter_name = args.results_formatter
416     if args.results_formatter_options:
417         configuration.results_formatter_options = args.results_formatter_options
418
419     # Default to using the BasicResultsFormatter if no formatter is specified.
420     if configuration.results_formatter_name is None:
421         configuration.results_formatter_name = (
422             "lldbsuite.test_event.formatter.results_formatter.ResultsFormatter")
423
424     # Reproducer arguments
425     if args.capture_path and args.replay_path:
426         logging.error('Cannot specify both a capture and a replay path.')
427         sys.exit(-1)
428
429     if args.capture_path:
430         configuration.capture_path = args.capture_path
431
432     if args.replay_path:
433         configuration.replay_path = args.replay_path
434
435     # rerun-related arguments
436     configuration.rerun_all_issues = args.rerun_all_issues
437
438     if args.lldb_platform_name:
439         configuration.lldb_platform_name = args.lldb_platform_name
440     if args.lldb_platform_url:
441         configuration.lldb_platform_url = args.lldb_platform_url
442     if args.lldb_platform_working_dir:
443         configuration.lldb_platform_working_dir = args.lldb_platform_working_dir
444     if args.test_build_dir:
445         configuration.test_build_dir = args.test_build_dir
446     if args.lldb_module_cache_dir:
447         configuration.lldb_module_cache_dir = args.lldb_module_cache_dir
448     else:
449         configuration.lldb_module_cache_dir = os.path.join(
450             configuration.test_build_dir, 'module-cache-lldb')
451     if args.clang_module_cache_dir:
452         configuration.clang_module_cache_dir = args.clang_module_cache_dir
453     else:
454         configuration.clang_module_cache_dir = os.path.join(
455             configuration.test_build_dir, 'module-cache-clang')
456
457     if args.lldb_libs_dir:
458         configuration.lldb_libs_dir = args.lldb_libs_dir
459
460     if args.enabled_plugins:
461         configuration.enabled_plugins = args.enabled_plugins
462
463     # Gather all the dirs passed on the command line.
464     if len(args.args) > 0:
465         configuration.testdirs = [os.path.realpath(os.path.abspath(x)) for x in args.args]
466
467     lldbtest_config.codesign_identity = args.codesign_identity
468
469
470 def setupTestResults():
471     """Sets up test results-related objects based on arg settings."""
472     # Setup the results formatter configuration.
473     formatter_config = formatter.FormatterConfig()
474     formatter_config.filename = configuration.results_filename
475     formatter_config.formatter_name = configuration.results_formatter_name
476     formatter_config.formatter_options = (
477         configuration.results_formatter_options)
478
479     # Create the results formatter.
480     formatter_spec = formatter.create_results_formatter(
481         formatter_config)
482     if formatter_spec is not None and formatter_spec.formatter is not None:
483         configuration.results_formatter_object = formatter_spec.formatter
484
485         # Send an initialize message to the formatter.
486         initialize_event = EventBuilder.bare_event("initialize")
487         initialize_event["worker_count"] = 1
488
489         formatter_spec.formatter.handle_event(initialize_event)
490
491         # Make sure we clean up the formatter on shutdown.
492         if formatter_spec.cleanup_func is not None:
493             atexit.register(formatter_spec.cleanup_func)
494
495
496 def setupSysPath():
497     """
498     Add LLDB.framework/Resources/Python to the search paths for modules.
499     As a side effect, we also discover the 'lldb' executable and export it here.
500     """
501
502     # Get the directory containing the current script.
503     if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ:
504         scriptPath = os.environ["DOTEST_SCRIPT_DIR"]
505     else:
506         scriptPath = os.path.dirname(os.path.realpath(__file__))
507     if not scriptPath.endswith('test'):
508         print("This script expects to reside in lldb's test directory.")
509         sys.exit(-1)
510
511     os.environ["LLDB_TEST"] = scriptPath
512     os.environ["LLDB_TEST_SRC"] = lldbsuite.lldb_test_root
513
514     # Set up the root build directory.
515     if not configuration.test_build_dir:
516         raise Exception("test_build_dir is not set")
517     configuration.test_build_dir = os.path.abspath(configuration.test_build_dir)
518
519     # Set up the LLDB_SRC environment variable, so that the tests can locate
520     # the LLDB source code.
521     os.environ["LLDB_SRC"] = lldbsuite.lldb_root
522
523     pluginPath = os.path.join(scriptPath, 'plugins')
524     toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode')
525     toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server')
526
527     # Insert script dir, plugin dir and lldb-server dir to the sys.path.
528     sys.path.insert(0, pluginPath)
529     # Adding test/tools/lldb-vscode to the path makes it easy to
530     # "import lldb_vscode_testcase" from the VSCode tests
531     sys.path.insert(0, toolsLLDBVSCode)
532     # Adding test/tools/lldb-server to the path makes it easy
533     sys.path.insert(0, toolsLLDBServerPath)
534     # to "import lldbgdbserverutils" from the lldb-server tests
535
536     # This is the root of the lldb git/svn checkout
537     # When this changes over to a package instead of a standalone script, this
538     # will be `lldbsuite.lldb_root`
539     lldbRootDirectory = lldbsuite.lldb_root
540
541     # Some of the tests can invoke the 'lldb' command directly.
542     # We'll try to locate the appropriate executable right here.
543
544     # The lldb executable can be set from the command line
545     # if it's not set, we try to find it now
546     # first, we try the environment
547     if not lldbtest_config.lldbExec:
548         # First, you can define an environment variable LLDB_EXEC specifying the
549         # full pathname of the lldb executable.
550         if "LLDB_EXEC" in os.environ:
551             lldbtest_config.lldbExec = os.environ["LLDB_EXEC"]
552
553     if not lldbtest_config.lldbExec:
554         # Last, check the path
555         lldbtest_config.lldbExec = which('lldb')
556
557     if lldbtest_config.lldbExec and not is_exe(lldbtest_config.lldbExec):
558         print(
559             "'{}' is not a path to a valid executable".format(
560                 lldbtest_config.lldbExec))
561         lldbtest_config.lldbExec = None
562
563     if not lldbtest_config.lldbExec:
564         print("The 'lldb' executable cannot be located.  Some of the tests may not be run as a result.")
565         sys.exit(-1)
566
567     # confusingly, this is the "bin" directory
568     lldbLibDir = os.path.dirname(lldbtest_config.lldbExec)
569     os.environ["LLDB_LIB_DIR"] = lldbLibDir
570     lldbImpLibDir = configuration.lldb_libs_dir
571     os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir
572     print("LLDB library dir:", os.environ["LLDB_LIB_DIR"])
573     print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"])
574     os.system('%s -v' % lldbtest_config.lldbExec)
575
576     lldbDir = os.path.dirname(lldbtest_config.lldbExec)
577
578     lldbVSCodeExec = os.path.join(lldbDir, "lldb-vscode")
579     if is_exe(lldbVSCodeExec):
580         os.environ["LLDBVSCODE_EXEC"] = lldbVSCodeExec
581     else:
582         if not configuration.shouldSkipBecauseOfCategories(["lldb-vscode"]):
583             print(
584                 "The 'lldb-vscode' executable cannot be located.  The lldb-vscode tests can not be run as a result.")
585             configuration.skip_categories.append("lldb-vscode")
586
587     lldbPythonDir = None  # The directory that contains 'lldb/__init__.py'
588     if not configuration.lldb_framework_path and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")):
589         configuration.lldb_framework_path = os.path.join(lldbLibDir, "LLDB.framework")
590     if configuration.lldb_framework_path:
591         lldbtest_config.lldb_framework_path = configuration.lldb_framework_path
592         candidatePath = os.path.join(
593             configuration.lldb_framework_path, 'Resources', 'Python')
594         if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')):
595             lldbPythonDir = candidatePath
596         if not lldbPythonDir:
597             print(
598                 'Resources/Python/lldb/__init__.py was not found in ' +
599                 configuration.lldb_framework_path)
600             sys.exit(-1)
601     else:
602         # If our lldb supports the -P option, use it to find the python path:
603         init_in_python_dir = os.path.join('lldb', '__init__.py')
604
605         lldb_dash_p_result = subprocess.check_output(
606             [lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True)
607
608         if lldb_dash_p_result and not lldb_dash_p_result.startswith(
609                 ("<", "lldb: invalid option:")) and not lldb_dash_p_result.startswith("Traceback"):
610             lines = lldb_dash_p_result.splitlines()
611
612             # Workaround for readline vs libedit issue on FreeBSD.  If stdout
613             # is not a terminal Python executes
614             #     rl_variable_bind ("enable-meta-key", "off");
615             # This produces a warning with FreeBSD's libedit because the
616             # enable-meta-key variable is unknown.  Not an issue on Apple
617             # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__
618             # around the call.  See http://bugs.python.org/issue19884 for more
619             # information.  For now we just discard the warning output.
620             if len(lines) >= 1 and lines[0].startswith(
621                     "bind: Invalid command"):
622                 lines.pop(0)
623
624             # Taking the last line because lldb outputs
625             # 'Cannot read termcap database;\nusing dumb terminal settings.\n'
626             # before the path
627             if len(lines) >= 1 and os.path.isfile(
628                     os.path.join(lines[-1], init_in_python_dir)):
629                 lldbPythonDir = lines[-1]
630                 if "freebsd" in sys.platform or "linux" in sys.platform:
631                     os.environ['LLDB_LIB_DIR'] = os.path.join(
632                         lldbPythonDir, '..', '..')
633
634         if not lldbPythonDir:
635             print(
636                 "Unable to load lldb extension module.  Possible reasons for this include:")
637             print("  1) LLDB was built with LLDB_ENABLE_PYTHON=0")
638             print(
639                 "  2) PYTHONPATH and PYTHONHOME are not set correctly.  PYTHONHOME should refer to")
640             print(
641                 "     the version of Python that LLDB built and linked against, and PYTHONPATH")
642             print(
643                 "     should contain the Lib directory for the same python distro, as well as the")
644             print("     location of LLDB\'s site-packages folder.")
645             print(
646                 "  3) A different version of Python than that which was built against is exported in")
647             print("     the system\'s PATH environment variable, causing conflicts.")
648             print(
649                 "  4) The executable '%s' could not be found.  Please check " %
650                 lldbtest_config.lldbExec)
651             print("     that it exists and is executable.")
652
653     if lldbPythonDir:
654         lldbPythonDir = os.path.normpath(lldbPythonDir)
655         # Some of the code that uses this path assumes it hasn't resolved the Versions... link.
656         # If the path we've constructed looks like that, then we'll strip out
657         # the Versions/A part.
658         (before, frameWithVersion, after) = lldbPythonDir.rpartition(
659             "LLDB.framework/Versions/A")
660         if frameWithVersion != "":
661             lldbPythonDir = before + "LLDB.framework" + after
662
663         lldbPythonDir = os.path.abspath(lldbPythonDir)
664
665         # If tests need to find LLDB_FRAMEWORK, now they can do it
666         os.environ["LLDB_FRAMEWORK"] = os.path.dirname(
667             os.path.dirname(lldbPythonDir))
668
669         # This is to locate the lldb.py module.  Insert it right after
670         # sys.path[0].
671         sys.path[1:1] = [lldbPythonDir]
672
673
674 def visit_file(dir, name):
675     # Try to match the regexp pattern, if specified.
676     if configuration.regexp:
677         if not re.search(configuration.regexp, name):
678             # We didn't match the regex, we're done.
679             return
680
681     if configuration.skip_tests:
682         for file_regexp in configuration.skip_tests:
683             if re.search(file_regexp, name):
684                 return
685
686     # We found a match for our test.  Add it to the suite.
687
688     # Update the sys.path first.
689     if not sys.path.count(dir):
690         sys.path.insert(0, dir)
691     base = os.path.splitext(name)[0]
692
693     # Thoroughly check the filterspec against the base module and admit
694     # the (base, filterspec) combination only when it makes sense.
695
696     def check(obj, parts):
697         for part in parts:
698             try:
699                 parent, obj = obj, getattr(obj, part)
700             except AttributeError:
701                 # The filterspec has failed.
702                 return False
703         return True
704
705     module = __import__(base)
706
707     def iter_filters():
708         for filterspec in configuration.filters:
709             parts = filterspec.split('.')
710             if check(module, parts):
711                 yield filterspec
712             elif parts[0] == base and len(parts) > 1 and check(module, parts[1:]):
713                 yield '.'.join(parts[1:])
714             else:
715                 for key,value in module.__dict__.items():
716                     if check(value, parts):
717                         yield key + '.' + filterspec
718
719     filtered = False
720     for filterspec in iter_filters():
721         filtered = True
722         print("adding filter spec %s to module %s" % (filterspec, repr(module)))
723         tests = unittest2.defaultTestLoader.loadTestsFromName(filterspec, module)
724         configuration.suite.addTests(tests)
725
726     # Forgo this module if the (base, filterspec) combo is invalid
727     if configuration.filters and not filtered:
728         return
729
730     if not filtered:
731         # Add the entire file's worth of tests since we're not filtered.
732         # Also the fail-over case when the filterspec branch
733         # (base, filterspec) combo doesn't make sense.
734         configuration.suite.addTests(
735             unittest2.defaultTestLoader.loadTestsFromName(base))
736
737
738 def visit(prefix, dir, names):
739     """Visitor function for os.path.walk(path, visit, arg)."""
740
741     dir_components = set(dir.split(os.sep))
742     excluded_components = set(['.svn', '.git'])
743     if dir_components.intersection(excluded_components):
744         return
745
746     # Gather all the Python test file names that follow the Test*.py pattern.
747     python_test_files = [
748         name
749         for name in names
750         if name.endswith('.py') and name.startswith(prefix)]
751
752     # Visit all the python test files.
753     for name in python_test_files:
754         try:
755             # Ensure we error out if we have multiple tests with the same
756             # base name.
757             # Future improvement: find all the places where we work with base
758             # names and convert to full paths.  We have directory structure
759             # to disambiguate these, so we shouldn't need this constraint.
760             if name in configuration.all_tests:
761                 raise Exception("Found multiple tests with the name %s" % name)
762             configuration.all_tests.add(name)
763
764             # Run the relevant tests in the python file.
765             visit_file(dir, name)
766         except Exception as ex:
767             # Convert this exception to a test event error for the file.
768             test_filename = os.path.abspath(os.path.join(dir, name))
769             if configuration.results_formatter_object is not None:
770                 # Grab the backtrace for the exception.
771                 import traceback
772                 backtrace = traceback.format_exc()
773
774                 # Generate the test event.
775                 configuration.results_formatter_object.handle_event(
776                     EventBuilder.event_for_job_test_add_error(
777                         test_filename, ex, backtrace))
778             raise
779
780
781 # ======================================== #
782 #                                          #
783 # Execution of the test driver starts here #
784 #                                          #
785 # ======================================== #
786
787
788 def checkDsymForUUIDIsNotOn():
789     cmd = ["defaults", "read", "com.apple.DebugSymbols"]
790     process = subprocess.Popen(
791         cmd,
792         stdout=subprocess.PIPE,
793         stderr=subprocess.STDOUT)
794     cmd_output = process.stdout.read()
795     output_str = cmd_output.decode("utf-8")
796     if "DBGFileMappedPaths = " in output_str:
797         print("%s =>" % ' '.join(cmd))
798         print(output_str)
799         print(
800             "Disable automatic lookup and caching of dSYMs before running the test suite!")
801         print("Exiting...")
802         sys.exit(0)
803
804
805 def exitTestSuite(exitCode=None):
806     # lldb.py does SBDebugger.Initialize().
807     # Call SBDebugger.Terminate() on exit.
808     import lldb
809     lldb.SBDebugger.Terminate()
810     if exitCode:
811         sys.exit(exitCode)
812
813
814 def getVersionForSDK(sdk):
815     sdk = str.lower(sdk)
816     full_path = seven.get_command_output('xcrun -sdk %s --show-sdk-path' % sdk)
817     basename = os.path.basename(full_path)
818     basename = os.path.splitext(basename)[0]
819     basename = str.lower(basename)
820     ver = basename.replace(sdk, '')
821     return ver
822
823
824 def setDefaultTripleForPlatform():
825     if configuration.lldb_platform_name == 'ios-simulator':
826         triple_str = 'x86_64-apple-ios%s' % (
827             getVersionForSDK('iphonesimulator'))
828         os.environ['TRIPLE'] = triple_str
829         return {'TRIPLE': triple_str}
830     return {}
831
832
833 def checkCompiler():
834     # Add some intervention here to sanity check that the compiler requested is sane.
835     # If found not to be an executable program, we abort.
836     c = configuration.compiler
837     if which(c):
838         return
839
840     if not sys.platform.startswith("darwin"):
841         raise Exception(c + " is not a valid compiler")
842
843     pipe = subprocess.Popen(
844         ['xcrun', '-find', c], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
845     cmd_output = pipe.stdout.read()
846     if not cmd_output or "not found" in cmd_output:
847         raise Exception(c + " is not a valid compiler")
848
849     configuration.compiler = cmd_output.split('\n')[0]
850     print("'xcrun -find %s' returning %s" % (c, configuration.compiler))
851
852 def canRunLibcxxTests():
853     from lldbsuite.test import lldbplatformutil
854
855     platform = lldbplatformutil.getPlatform()
856
857     if lldbplatformutil.target_is_android() or lldbplatformutil.platformIsDarwin():
858         return True, "libc++ always present"
859
860     if platform == "linux":
861         if os.path.isdir("/usr/include/c++/v1"):
862             return True, "Headers found, let's hope they work"
863         with tempfile.NamedTemporaryFile() as f:
864             cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.name, "-"]
865             p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
866             _, stderr = p.communicate("#include <algorithm>\nint main() {}")
867             if not p.returncode:
868                 return True, "Compiling with -stdlib=libc++ works"
869             return False, "Compiling with -stdlib=libc++ fails with the error: %s" % stderr
870
871     return False, "Don't know how to build with libc++ on %s" % platform
872
873 def checkLibcxxSupport():
874     result, reason = canRunLibcxxTests()
875     if result:
876         return # libc++ supported
877     if "libc++" in configuration.categories_list:
878         return # libc++ category explicitly requested, let it run.
879     print("Libc++ tests will not be run because: " + reason)
880     configuration.skip_categories.append("libc++")
881
882 def canRunLibstdcxxTests():
883     from lldbsuite.test import lldbplatformutil
884
885     platform = lldbplatformutil.getPlatform()
886     if lldbplatformutil.target_is_android():
887         platform = "android"
888     if platform == "linux":
889         return True, "libstdcxx always present"
890     return False, "Don't know how to build with libstdcxx on %s" % platform
891
892 def checkLibstdcxxSupport():
893     result, reason = canRunLibstdcxxTests()
894     if result:
895         return # libstdcxx supported
896     if "libstdcxx" in configuration.categories_list:
897         return # libstdcxx category explicitly requested, let it run.
898     print("libstdcxx tests will not be run because: " + reason)
899     configuration.skip_categories.append("libstdcxx")
900
901 def canRunWatchpointTests():
902     from lldbsuite.test import lldbplatformutil
903
904     platform = lldbplatformutil.getPlatform()
905     if platform == "netbsd":
906         if os.geteuid() == 0:
907             return True, "root can always write dbregs"
908         try:
909             output = subprocess.check_output(["/sbin/sysctl", "-n",
910               "security.models.extensions.user_set_dbregs"]).decode().strip()
911             if output == "1":
912                 return True, "security.models.extensions.user_set_dbregs enabled"
913         except subprocess.CalledProcessError:
914             pass
915         return False, "security.models.extensions.user_set_dbregs disabled"
916     return True, "watchpoint support available"
917
918 def checkWatchpointSupport():
919     result, reason = canRunWatchpointTests()
920     if result:
921         return # watchpoints supported
922     if "watchpoint" in configuration.categories_list:
923         return # watchpoint category explicitly requested, let it run.
924     print("watchpoint tests will not be run because: " + reason)
925     configuration.skip_categories.append("watchpoint")
926
927 def checkDebugInfoSupport():
928     import lldb
929
930     platform = lldb.selected_platform.GetTriple().split('-')[2]
931     compiler = configuration.compiler
932     skipped = []
933     for cat in test_categories.debug_info_categories:
934         if cat in configuration.categories_list:
935             continue # Category explicitly requested, let it run.
936         if test_categories.is_supported_on_platform(cat, platform, compiler):
937             continue
938         configuration.skip_categories.append(cat)
939         skipped.append(cat)
940     if skipped:
941         print("Skipping following debug info categories:", skipped)
942
943 def run_suite():
944     # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults
945     # does not exist before proceeding to running the test suite.
946     if sys.platform.startswith("darwin"):
947         checkDsymForUUIDIsNotOn()
948
949     # Start the actions by first parsing the options while setting up the test
950     # directories, followed by setting up the search paths for lldb utilities;
951     # then, we walk the directory trees and collect the tests into our test suite.
952     #
953     parseOptionsAndInitTestdirs()
954
955     # Setup test results (test results formatter and output handling).
956     setupTestResults()
957
958     setupSysPath()
959
960     import lldbconfig
961     if configuration.capture_path or configuration.replay_path:
962         lldbconfig.INITIALIZE = False
963     import lldb
964
965     if configuration.capture_path:
966         lldb.SBReproducer.Capture(configuration.capture_path)
967         lldb.SBReproducer.SetAutoGenerate(True)
968     elif configuration.replay_path:
969         lldb.SBReproducer.PassiveReplay(configuration.replay_path)
970
971     if not lldbconfig.INITIALIZE:
972         lldb.SBDebugger.Initialize()
973
974     # Use host platform by default.
975     lldb.selected_platform = lldb.SBPlatform.GetHostPlatform()
976
977     # Now we can also import lldbutil
978     from lldbsuite.test import lldbutil
979
980     if configuration.lldb_platform_name:
981         print("Setting up remote platform '%s'" %
982               (configuration.lldb_platform_name))
983         lldb.remote_platform = lldb.SBPlatform(
984             configuration.lldb_platform_name)
985         if not lldb.remote_platform.IsValid():
986             print(
987                 "error: unable to create the LLDB platform named '%s'." %
988                 (configuration.lldb_platform_name))
989             exitTestSuite(1)
990         if configuration.lldb_platform_url:
991             # We must connect to a remote platform if a LLDB platform URL was
992             # specified
993             print(
994                 "Connecting to remote platform '%s' at '%s'..." %
995                 (configuration.lldb_platform_name, configuration.lldb_platform_url))
996             platform_connect_options = lldb.SBPlatformConnectOptions(
997                 configuration.lldb_platform_url)
998             err = lldb.remote_platform.ConnectRemote(platform_connect_options)
999             if err.Success():
1000                 print("Connected.")
1001             else:
1002                 print("error: failed to connect to remote platform using URL '%s': %s" % (
1003                     configuration.lldb_platform_url, err))
1004                 exitTestSuite(1)
1005         else:
1006             configuration.lldb_platform_url = None
1007
1008     platform_changes = setDefaultTripleForPlatform()
1009     first = True
1010     for key in platform_changes:
1011         if first:
1012             print("Environment variables setup for platform support:")
1013             first = False
1014         print("%s = %s" % (key, platform_changes[key]))
1015
1016     if configuration.lldb_platform_working_dir:
1017         print("Setting remote platform working directory to '%s'..." %
1018               (configuration.lldb_platform_working_dir))
1019         error = lldb.remote_platform.MakeDirectory(
1020             configuration.lldb_platform_working_dir, 448)  # 448 = 0o700
1021         if error.Fail():
1022             raise Exception("making remote directory '%s': %s" % (
1023                 configuration.lldb_platform_working_dir, error))
1024
1025         if not lldb.remote_platform.SetWorkingDirectory(
1026                 configuration.lldb_platform_working_dir):
1027             raise Exception("failed to set working directory '%s'" % configuration.lldb_platform_working_dir)
1028         lldb.selected_platform = lldb.remote_platform
1029     else:
1030         lldb.remote_platform = None
1031         configuration.lldb_platform_working_dir = None
1032         configuration.lldb_platform_url = None
1033
1034     # Set up the working directory.
1035     # Note that it's not dotest's job to clean this directory.
1036     lldbutil.mkdir_p(configuration.test_build_dir)
1037
1038     target_platform = lldb.selected_platform.GetTriple().split('-')[2]
1039
1040     checkLibcxxSupport()
1041     checkLibstdcxxSupport()
1042     checkWatchpointSupport()
1043     checkDebugInfoSupport()
1044
1045     # Don't do debugserver tests on anything except OS X.
1046     configuration.dont_do_debugserver_test = (
1047             "linux" in target_platform or
1048             "freebsd" in target_platform or
1049             "netbsd" in target_platform or
1050             "windows" in target_platform)
1051
1052     # Don't do lldb-server (llgs) tests on anything except Linux and Windows.
1053     configuration.dont_do_llgs_test = not (
1054             "linux" in target_platform or
1055             "netbsd" in target_platform or
1056             "windows" in target_platform)
1057
1058     for testdir in configuration.testdirs:
1059         for (dirpath, dirnames, filenames) in os.walk(testdir):
1060             visit('Test', dirpath, filenames)
1061
1062     #
1063     # Now that we have loaded all the test cases, run the whole test suite.
1064     #
1065
1066     # Install the control-c handler.
1067     unittest2.signals.installHandler()
1068
1069     lldbutil.mkdir_p(configuration.sdir_name)
1070     os.environ["LLDB_SESSION_DIRNAME"] = configuration.sdir_name
1071
1072     sys.stderr.write(
1073         "\nSession logs for test failures/errors/unexpected successes"
1074         " will go into directory '%s'\n" %
1075         configuration.sdir_name)
1076
1077     #
1078     # Invoke the default TextTestRunner to run the test suite
1079     #
1080     checkCompiler()
1081
1082     if configuration.verbose:
1083         print("compiler=%s" % configuration.compiler)
1084
1085     # Iterating over all possible architecture and compiler combinations.
1086     configString = "arch=%s compiler=%s" % (configuration.arch,
1087                                             configuration.compiler)
1088
1089     # Output the configuration.
1090     if configuration.verbose:
1091         sys.stderr.write("\nConfiguration: " + configString + "\n")
1092
1093     # First, write out the number of collected test cases.
1094     if configuration.verbose:
1095         sys.stderr.write(configuration.separator + "\n")
1096         sys.stderr.write(
1097             "Collected %d test%s\n\n" %
1098             (configuration.suite.countTestCases(),
1099              configuration.suite.countTestCases() != 1 and "s" or ""))
1100
1101     # Invoke the test runner.
1102     if configuration.count == 1:
1103         result = unittest2.TextTestRunner(
1104             stream=sys.stderr,
1105             verbosity=configuration.verbose,
1106             resultclass=test_result.LLDBTestResult).run(
1107             configuration.suite)
1108     else:
1109         # We are invoking the same test suite more than once.  In this case,
1110         # mark __ignore_singleton__ flag as True so the signleton pattern is
1111         # not enforced.
1112         test_result.LLDBTestResult.__ignore_singleton__ = True
1113         for i in range(configuration.count):
1114
1115             result = unittest2.TextTestRunner(
1116                 stream=sys.stderr,
1117                 verbosity=configuration.verbose,
1118                 resultclass=test_result.LLDBTestResult).run(
1119                 configuration.suite)
1120
1121     configuration.failed = not result.wasSuccessful()
1122
1123     if configuration.sdir_has_content and configuration.verbose:
1124         sys.stderr.write(
1125             "Session logs for test failures/errors/unexpected successes"
1126             " can be found in directory '%s'\n" %
1127             configuration.sdir_name)
1128
1129     if configuration.use_categories and len(
1130             configuration.failures_per_category) > 0:
1131         sys.stderr.write("Failures per category:\n")
1132         for category in configuration.failures_per_category:
1133             sys.stderr.write(
1134                 "%s - %d\n" %
1135                 (category, configuration.failures_per_category[category]))
1136
1137     # Exiting.
1138     exitTestSuite(configuration.failed)
1139
1140 if __name__ == "__main__":
1141     print(
1142         __file__ +
1143         " is for use as a module only.  It should not be run as a standalone script.")
1144     sys.exit(-1)