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