blob: 18b2e268b620dea026d9ba45c9ff17532634721a [file] [log] [blame]
Johnny Chen9707bb62010-06-25 21:14:08 +00001#!/usr/bin/env python
2
3"""
4A simple testing framework for lldb using python's unit testing framework.
5
6Tests for lldb are written as python scripts which take advantage of the script
7bridging provided by LLDB.framework to interact with lldb core.
8
9A specific naming pattern is followed by the .py script to be recognized as
10a module which implements a test scenario, namely, Test*.py.
11
12To specify the directories where "Test*.py" python test scripts are located,
13you need to pass in a list of directory names. By default, the current
14working directory is searched if nothing is specified on the command line.
Johnny Chen872aee12010-09-16 15:44:23 +000015
16Type:
17
18./dotest.py -h
19
20for available options.
Johnny Chen9707bb62010-06-25 21:14:08 +000021"""
22
Johnny Chen91960d32010-09-08 20:56:16 +000023import os, signal, sys, time
Johnny Chen75e28f92010-08-05 23:42:46 +000024import unittest2
Johnny Chen9707bb62010-06-25 21:14:08 +000025
Johnny Chen26901c82011-03-11 19:47:23 +000026def is_exe(fpath):
27 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
28
29# Find the full path to a program, or return None.
30def which(program):
31 fpath, fname = os.path.split(program)
32 if fpath:
33 if is_exe(program):
34 return program
35 else:
36 for path in os.environ["PATH"].split(os.pathsep):
37 exe_file = os.path.join(path, program)
38 if is_exe(exe_file):
39 return exe_file
40 return None
41
Johnny Chen877c7e42010-08-07 00:16:07 +000042class _WritelnDecorator(object):
43 """Used to decorate file-like objects with a handy 'writeln' method"""
44 def __init__(self,stream):
45 self.stream = stream
46
47 def __getattr__(self, attr):
48 if attr in ('stream', '__getstate__'):
49 raise AttributeError(attr)
50 return getattr(self.stream,attr)
51
52 def writeln(self, arg=None):
53 if arg:
54 self.write(arg)
55 self.write('\n') # text-mode streams translate to \r\n if needed
56
Johnny Chen9707bb62010-06-25 21:14:08 +000057#
58# Global variables:
59#
60
61# The test suite.
Johnny Chen75e28f92010-08-05 23:42:46 +000062suite = unittest2.TestSuite()
Johnny Chen9707bb62010-06-25 21:14:08 +000063
Johnny Chen4f93bf12010-12-10 00:51:23 +000064# By default, both command line and Python API tests are performed.
Johnny Chen3ebdacc2010-12-10 18:52:10 +000065# Use @python_api_test decorator, defined in lldbtest.py, to mark a test as
66# a Python API test.
Johnny Chen4f93bf12010-12-10 00:51:23 +000067dont_do_python_api_test = False
68
69# By default, both command line and Python API tests are performed.
Johnny Chen4f93bf12010-12-10 00:51:23 +000070just_do_python_api_test = False
71
Johnny Chen82e6b1e2010-12-01 22:47:54 +000072# The blacklist is optional (-b blacklistFile) and allows a central place to skip
73# testclass's and/or testclass.testmethod's.
74blacklist = None
75
76# The dictionary as a result of sourcing blacklistFile.
77blacklistConfig = {}
78
Johnny Chen9fdb0a92010-09-18 00:16:47 +000079# The config file is optional.
80configFile = None
81
Johnny Chend2acdb32010-11-16 22:42:58 +000082# Test suite repeat count. Can be overwritten with '-# count'.
83count = 1
84
Johnny Chenb40056b2010-09-21 00:09:27 +000085# The dictionary as a result of sourcing configFile.
86config = {}
87
Johnny Chen1a4d5e72011-03-04 01:35:22 +000088# The 'archs' and 'compilers' can be specified via either command line or configFile,
89# with the command line overriding the configFile. When specified, they should be
90# of the list type. For example, "-A x86_64^i386" => archs=['x86_64', 'i386'] and
91# "-C gcc^clang" => compilers=['gcc', 'clang'].
92archs = None
93compilers = None
94
Johnny Chen91960d32010-09-08 20:56:16 +000095# Delay startup in order for the debugger to attach.
96delay = False
97
Johnny Chend5362332011-01-29 01:21:04 +000098# Dump the Python sys.path variable. Use '-D' to dump sys.path.
Johnny Chen50bc6382011-01-29 01:16:52 +000099dumpSysPath = False
100
Johnny Chen7d6d8442010-12-03 19:59:35 +0000101# By default, failfast is False. Use '-F' to overwrite it.
102failfast = False
103
Johnny Chena224cd12010-11-08 01:21:03 +0000104# The filter (testclass.testmethod) used to admit tests into our test suite.
Johnny Chenb62436b2010-10-06 20:40:56 +0000105filterspec = None
106
Johnny Chena224cd12010-11-08 01:21:03 +0000107# If '-g' is specified, the filterspec is not exclusive. If a test module does
108# not contain testclass.testmethod which matches the filterspec, the whole test
109# module is still admitted into our test suite. fs4all flag defaults to True.
110fs4all = True
Johnny Chenb62436b2010-10-06 20:40:56 +0000111
Johnny Chenaf149a02010-09-16 17:11:30 +0000112# Ignore the build search path relative to this script to locate the lldb.py module.
113ignore = False
114
Johnny Chen548aefd2010-10-11 22:25:46 +0000115# By default, we skip long running test case. Use '-l' option to override.
Johnny Chen41998192010-10-01 22:59:49 +0000116skipLongRunningTest = True
117
Johnny Chen7c52ff12010-09-27 23:29:54 +0000118# The regular expression pattern to match against eligible filenames as our test cases.
119regexp = None
120
Johnny Chen548aefd2010-10-11 22:25:46 +0000121# By default, tests are executed in place and cleanups are performed afterwards.
122# Use '-r dir' option to relocate the tests and their intermediate files to a
123# different directory and to forgo any cleanups. The directory specified must
124# not exist yet.
125rdir = None
126
Johnny Chen125fc2b2010-10-21 16:55:35 +0000127# By default, recorded session info for errored/failed test are dumped into its
128# own file under a session directory named after the timestamp of the test suite
129# run. Use '-s session-dir-name' to specify a specific dir name.
130sdir_name = None
131
Johnny Chen63c2cba2010-10-29 22:20:36 +0000132# Set this flag if there is any session info dumped during the test run.
133sdir_has_content = False
134
Johnny Chen9707bb62010-06-25 21:14:08 +0000135# Default verbosity is 0.
136verbose = 0
137
138# By default, search from the current working directory.
139testdirs = [ os.getcwd() ]
140
Johnny Chen877c7e42010-08-07 00:16:07 +0000141# Separator string.
142separator = '-' * 70
143
Johnny Chen9707bb62010-06-25 21:14:08 +0000144
145def usage():
146 print """
147Usage: dotest.py [option] [args]
148where options:
149-h : print this help message and exit (also --help)
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000150-A : specify the architecture(s) to launch for the inferior process
151 -A i386 => launch inferior with i386 architecture
152 -A x86_64^i386 => launch inferior with x86_64 and i386 architectures
153-C : specify the compiler(s) used to build the inferior executable
154 -C clang => build debuggee using clang compiler
155 -C clang^gcc => build debuggee using clang and gcc compilers
Johnny Chen50bc6382011-01-29 01:16:52 +0000156-D : dump the Python sys.path variable
Johnny Chen4f93bf12010-12-10 00:51:23 +0000157-a : don't do lldb Python API tests
158 use @python_api_test to decorate a test case as lldb Python API test
Johnny Chen3ebdacc2010-12-10 18:52:10 +0000159+a : just do lldb Python API tests
Johnny Chencc659ad2010-12-10 19:02:23 +0000160 do not specify both '-a' and '+a' at the same time
Johnny Chen82e6b1e2010-12-01 22:47:54 +0000161-b : read a blacklist file specified after this option
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000162-c : read a config file specified after this option
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000163 the architectures and compilers (note the plurals) specified via '-A' and '-C'
164 will override those specified via a config file
Johnny Chenb40056b2010-09-21 00:09:27 +0000165 (see also lldb-trunk/example/test/usage-config)
Johnny Chen91960d32010-09-08 20:56:16 +0000166-d : delay startup for 10 seconds (in order for the debugger to attach)
Johnny Chen7d6d8442010-12-03 19:59:35 +0000167-F : failfast, stop the test suite on the first error/failure
Johnny Chen46be75d2010-10-11 16:19:48 +0000168-f : specify a filter, which consists of the test class name, a dot, followed by
Johnny Chen1a6e92a2010-11-08 20:17:04 +0000169 the test method, to only admit such test into the test suite
Johnny Chenb62436b2010-10-06 20:40:56 +0000170 e.g., -f 'ClassTypesTestCase.test_with_dwarf_and_python_api'
Johnny Chena224cd12010-11-08 01:21:03 +0000171-g : if specified, the filterspec by -f is not exclusive, i.e., if a test module
172 does not match the filterspec (testclass.testmethod), the whole module is
173 still admitted to the test suite
Johnny Chenaf149a02010-09-16 17:11:30 +0000174-i : ignore (don't bailout) if 'lldb.py' module cannot be located in the build
175 tree relative to this script; use PYTHONPATH to locate the module
Johnny Chen41998192010-10-01 22:59:49 +0000176-l : don't skip long running test
Johnny Chen7c52ff12010-09-27 23:29:54 +0000177-p : specify a regexp filename pattern for inclusion in the test suite
Johnny Chen548aefd2010-10-11 22:25:46 +0000178-r : specify a dir to relocate the tests and their intermediate files to;
179 the directory must not exist before running this test driver;
180 no cleanup of intermediate test files is performed in this case
Johnny Chen125fc2b2010-10-21 16:55:35 +0000181-s : specify the name of the dir created to store the session files of tests
182 with errored or failed status; if not specified, the test driver uses the
183 timestamp as the session dir name
Johnny Chend0c24b22010-08-23 17:10:44 +0000184-t : trace lldb command execution and result
Johnny Chen9707bb62010-06-25 21:14:08 +0000185-v : do verbose mode of unittest framework
Johnny Chene47649c2010-10-07 02:04:14 +0000186-w : insert some wait time (currently 0.5 sec) between consecutive test cases
Johnny Chend2acdb32010-11-16 22:42:58 +0000187-# : Repeat the test suite for a specified number of times
Johnny Chen9707bb62010-06-25 21:14:08 +0000188
189and:
Johnny Chen9656ab22010-10-22 19:00:18 +0000190args : specify a list of directory names to search for test modules named after
191 Test*.py (test discovery)
Johnny Chen9707bb62010-06-25 21:14:08 +0000192 if empty, search from the curret working directory, instead
Johnny Chen58f93922010-06-29 23:10:39 +0000193
Johnny Chen9656ab22010-10-22 19:00:18 +0000194Examples:
195
Johnny Chena224cd12010-11-08 01:21:03 +0000196This is an example of using the -f option to pinpoint to a specfic test class
197and test method to be run:
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000198
Johnny Chena224cd12010-11-08 01:21:03 +0000199$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000200----------------------------------------------------------------------
201Collected 1 test
202
203test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase)
204Test 'frame variable this' when stopped on a class constructor. ... ok
205
206----------------------------------------------------------------------
207Ran 1 test in 1.396s
208
209OK
Johnny Chen9656ab22010-10-22 19:00:18 +0000210
211And this is an example of using the -p option to run a single file (the filename
212matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'):
213
214$ ./dotest.py -v -p ObjC
215----------------------------------------------------------------------
216Collected 4 tests
217
218test_break_with_dsym (TestObjCMethods.FoundationTestCase)
219Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'. ... ok
220test_break_with_dwarf (TestObjCMethods.FoundationTestCase)
221Test setting objc breakpoints using 'regexp-break' and 'breakpoint set'. ... ok
222test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase)
223Lookup objective-c data types and evaluate expressions. ... ok
224test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase)
225Lookup objective-c data types and evaluate expressions. ... ok
226
227----------------------------------------------------------------------
228Ran 4 tests in 16.661s
229
230OK
Johnny Chen6ad7e5e2010-10-21 00:47:52 +0000231
Johnny Chen58f93922010-06-29 23:10:39 +0000232Running of this script also sets up the LLDB_TEST environment variable so that
Johnny Chenaf149a02010-09-16 17:11:30 +0000233individual test cases can locate their supporting files correctly. The script
234tries to set up Python's search paths for modules by looking at the build tree
Johnny Chena85859f2010-11-11 22:14:56 +0000235relative to this script. See also the '-i' option in the following example.
236
237Finally, this is an example of using the lldb.py module distributed/installed by
238Xcode4 to run against the tests under the 'forward' directory, and with the '-w'
239option to add some delay between two tests. It uses ARCH=x86_64 to specify that
240as the architecture and CC=clang to specify the compiler used for the test run:
241
242$ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward
243
244Session logs for test failures/errors will go into directory '2010-11-11-13_56_16'
245----------------------------------------------------------------------
246Collected 2 tests
247
248test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
249Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
250test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase)
251Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok
252
253----------------------------------------------------------------------
254Ran 2 tests in 5.659s
255
256OK
257
258The 'Session ...' verbiage is recently introduced (see also the '-s' option) to
259notify the directory containing the session logs for test failures or errors.
260In case there is any test failure/error, a similar message is appended at the
261end of the stderr output for your convenience.
Johnny Chenfde69bc2010-09-14 22:01:40 +0000262
263Environment variables related to loggings:
264
265o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
266 with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
267
268o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
269 'process.gdb-remote' subsystem with a default option of 'packets' if
270 GDB_REMOTE_LOG_OPTION is not defined.
Johnny Chen9707bb62010-06-25 21:14:08 +0000271"""
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000272 sys.exit(0)
Johnny Chen9707bb62010-06-25 21:14:08 +0000273
274
Johnny Chenaf149a02010-09-16 17:11:30 +0000275def parseOptionsAndInitTestdirs():
276 """Initialize the list of directories containing our unittest scripts.
277
278 '-h/--help as the first option prints out usage info and exit the program.
279 """
280
Johnny Chen4f93bf12010-12-10 00:51:23 +0000281 global dont_do_python_api_test
282 global just_do_python_api_test
Johnny Chen82e6b1e2010-12-01 22:47:54 +0000283 global blacklist
284 global blacklistConfig
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000285 global configFile
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000286 global archs
287 global compilers
Johnny Chend2acdb32010-11-16 22:42:58 +0000288 global count
Johnny Chenaf149a02010-09-16 17:11:30 +0000289 global delay
Johnny Chen50bc6382011-01-29 01:16:52 +0000290 global dumpSysPath
Johnny Chen7d6d8442010-12-03 19:59:35 +0000291 global failfast
Johnny Chenb62436b2010-10-06 20:40:56 +0000292 global filterspec
293 global fs4all
Johnny Chen7c52ff12010-09-27 23:29:54 +0000294 global ignore
Johnny Chen41998192010-10-01 22:59:49 +0000295 global skipLongRunningTest
Johnny Chen7c52ff12010-09-27 23:29:54 +0000296 global regexp
Johnny Chen548aefd2010-10-11 22:25:46 +0000297 global rdir
Johnny Chen125fc2b2010-10-21 16:55:35 +0000298 global sdir_name
Johnny Chenaf149a02010-09-16 17:11:30 +0000299 global verbose
300 global testdirs
301
302 if len(sys.argv) == 1:
303 return
304
305 # Process possible trace and/or verbose flag, among other things.
306 index = 1
Johnny Chence2212c2010-10-07 15:41:55 +0000307 while index < len(sys.argv):
Johnny Chen4f93bf12010-12-10 00:51:23 +0000308 if sys.argv[index].startswith('-') or sys.argv[index].startswith('+'):
309 # We should continue processing...
310 pass
311 else:
Johnny Chenaf149a02010-09-16 17:11:30 +0000312 # End of option processing.
313 break
314
315 if sys.argv[index].find('-h') != -1:
316 usage()
Johnny Chen012cba12011-01-26 19:07:42 +0000317 elif sys.argv[index].startswith('-A'):
318 # Increment by 1 to fetch the ARCH spec.
319 index += 1
320 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
321 usage()
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000322 archSpec = sys.argv[index]
323 if archSpec.find('^') != -1:
324 archs = archSpec.split('^')
325 else:
326 os.environ["ARCH"] = archSpec
Johnny Chen012cba12011-01-26 19:07:42 +0000327 index += 1
328 elif sys.argv[index].startswith('-C'):
329 # Increment by 1 to fetch the CC spec.
330 index += 1
331 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
332 usage()
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000333 ccSpec = sys.argv[index]
334 if ccSpec.find('^') != -1:
335 compilers = ccSpec.split('^')
336 else:
337 os.environ["CC"] = ccSpec
Johnny Chen012cba12011-01-26 19:07:42 +0000338 index += 1
Johnny Chen50bc6382011-01-29 01:16:52 +0000339 elif sys.argv[index].startswith('-D'):
340 dumpSysPath = True
341 index += 1
Johnny Chen4f93bf12010-12-10 00:51:23 +0000342 elif sys.argv[index].startswith('-a'):
343 dont_do_python_api_test = True
344 index += 1
345 elif sys.argv[index].startswith('+a'):
346 just_do_python_api_test = True
347 index += 1
Johnny Chen82e6b1e2010-12-01 22:47:54 +0000348 elif sys.argv[index].startswith('-b'):
349 # Increment by 1 to fetch the blacklist file name option argument.
350 index += 1
351 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
352 usage()
353 blacklistFile = sys.argv[index]
354 if not os.path.isfile(blacklistFile):
355 print "Blacklist file:", blacklistFile, "does not exist!"
356 usage()
357 index += 1
358 # Now read the blacklist contents and assign it to blacklist.
359 execfile(blacklistFile, globals(), blacklistConfig)
360 blacklist = blacklistConfig.get('blacklist')
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000361 elif sys.argv[index].startswith('-c'):
362 # Increment by 1 to fetch the config file name option argument.
363 index += 1
364 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
365 usage()
366 configFile = sys.argv[index]
367 if not os.path.isfile(configFile):
368 print "Config file:", configFile, "does not exist!"
369 usage()
370 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000371 elif sys.argv[index].startswith('-d'):
372 delay = True
373 index += 1
Johnny Chen7d6d8442010-12-03 19:59:35 +0000374 elif sys.argv[index].startswith('-F'):
375 failfast = True
376 index += 1
Johnny Chenb62436b2010-10-06 20:40:56 +0000377 elif sys.argv[index].startswith('-f'):
378 # Increment by 1 to fetch the filter spec.
379 index += 1
380 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
381 usage()
382 filterspec = sys.argv[index]
383 index += 1
384 elif sys.argv[index].startswith('-g'):
Johnny Chena224cd12010-11-08 01:21:03 +0000385 fs4all = False
Johnny Chenb62436b2010-10-06 20:40:56 +0000386 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000387 elif sys.argv[index].startswith('-i'):
388 ignore = True
389 index += 1
Johnny Chen41998192010-10-01 22:59:49 +0000390 elif sys.argv[index].startswith('-l'):
391 skipLongRunningTest = False
392 index += 1
Johnny Chen7c52ff12010-09-27 23:29:54 +0000393 elif sys.argv[index].startswith('-p'):
394 # Increment by 1 to fetch the reg exp pattern argument.
395 index += 1
396 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
397 usage()
398 regexp = sys.argv[index]
399 index += 1
Johnny Chen548aefd2010-10-11 22:25:46 +0000400 elif sys.argv[index].startswith('-r'):
401 # Increment by 1 to fetch the relocated directory argument.
402 index += 1
403 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
404 usage()
405 rdir = os.path.abspath(sys.argv[index])
406 if os.path.exists(rdir):
407 print "Relocated directory:", rdir, "must not exist!"
408 usage()
409 index += 1
Johnny Chen125fc2b2010-10-21 16:55:35 +0000410 elif sys.argv[index].startswith('-s'):
411 # Increment by 1 to fetch the session dir name.
412 index += 1
413 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
414 usage()
415 sdir_name = sys.argv[index]
416 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000417 elif sys.argv[index].startswith('-t'):
418 os.environ["LLDB_COMMAND_TRACE"] = "YES"
419 index += 1
420 elif sys.argv[index].startswith('-v'):
421 verbose = 2
422 index += 1
Johnny Chene47649c2010-10-07 02:04:14 +0000423 elif sys.argv[index].startswith('-w'):
424 os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] = 'YES'
425 index += 1
Johnny Chend2acdb32010-11-16 22:42:58 +0000426 elif sys.argv[index].startswith('-#'):
427 # Increment by 1 to fetch the repeat count argument.
428 index += 1
429 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
430 usage()
431 count = int(sys.argv[index])
432 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000433 else:
434 print "Unknown option: ", sys.argv[index]
435 usage()
Johnny Chenaf149a02010-09-16 17:11:30 +0000436
Johnny Chencc659ad2010-12-10 19:02:23 +0000437 # Do not specify both '-a' and '+a' at the same time.
438 if dont_do_python_api_test and just_do_python_api_test:
439 usage()
440
Johnny Chenaf149a02010-09-16 17:11:30 +0000441 # Gather all the dirs passed on the command line.
442 if len(sys.argv) > index:
443 testdirs = map(os.path.abspath, sys.argv[index:])
444
Johnny Chen548aefd2010-10-11 22:25:46 +0000445 # If '-r dir' is specified, the tests should be run under the relocated
446 # directory. Let's copy the testdirs over.
447 if rdir:
448 from shutil import copytree, ignore_patterns
449
450 tmpdirs = []
451 for srcdir in testdirs:
452 dstdir = os.path.join(rdir, os.path.basename(srcdir))
453 # Don't copy the *.pyc and .svn stuffs.
454 copytree(srcdir, dstdir, ignore=ignore_patterns('*.pyc', '.svn'))
455 tmpdirs.append(dstdir)
456
457 # This will be our modified testdirs.
458 testdirs = tmpdirs
459
460 # With '-r dir' specified, there's no cleanup of intermediate test files.
461 os.environ["LLDB_DO_CLEANUP"] = 'NO'
462
463 # If testdirs is ['test'], the make directory has already been copied
464 # recursively and is contained within the rdir/test dir. For anything
465 # else, we would need to copy over the make directory and its contents,
466 # so that, os.listdir(rdir) looks like, for example:
467 #
468 # array_types conditional_break make
469 #
470 # where the make directory contains the Makefile.rules file.
471 if len(testdirs) != 1 or os.path.basename(testdirs[0]) != 'test':
472 # Don't copy the .svn stuffs.
473 copytree('make', os.path.join(rdir, 'make'),
474 ignore=ignore_patterns('.svn'))
475
476 #print "testdirs:", testdirs
477
Johnny Chenb40056b2010-09-21 00:09:27 +0000478 # Source the configFile if specified.
479 # The side effect, if any, will be felt from this point on. An example
480 # config file may be these simple two lines:
481 #
482 # sys.stderr = open("/tmp/lldbtest-stderr", "w")
483 # sys.stdout = open("/tmp/lldbtest-stdout", "w")
484 #
485 # which will reassign the two file objects to sys.stderr and sys.stdout,
486 # respectively.
487 #
488 # See also lldb-trunk/example/test/usage-config.
489 global config
490 if configFile:
491 # Pass config (a dictionary) as the locals namespace for side-effect.
492 execfile(configFile, globals(), config)
493 #print "config:", config
494 #print "sys.stderr:", sys.stderr
495 #print "sys.stdout:", sys.stdout
496
Johnny Chenaf149a02010-09-16 17:11:30 +0000497
Johnny Chen9707bb62010-06-25 21:14:08 +0000498def setupSysPath():
Johnny Chen8a3c0432011-03-11 20:13:06 +0000499 """
500 Add LLDB.framework/Resources/Python to the search paths for modules.
501 As a side effect, we also discover the 'lldb' executable and export it here.
502 """
Johnny Chen9707bb62010-06-25 21:14:08 +0000503
Johnny Chen548aefd2010-10-11 22:25:46 +0000504 global rdir
505 global testdirs
Johnny Chen50bc6382011-01-29 01:16:52 +0000506 global dumpSysPath
Johnny Chen548aefd2010-10-11 22:25:46 +0000507
Johnny Chen9707bb62010-06-25 21:14:08 +0000508 # Get the directory containing the current script.
Johnny Chen0de6ab52011-01-19 02:10:40 +0000509 if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ:
510 scriptPath = os.environ["DOTEST_SCRIPT_DIR"]
511 else:
512 scriptPath = sys.path[0]
Johnny Chena1affab2010-07-03 03:41:59 +0000513 if not scriptPath.endswith('test'):
Johnny Chen9707bb62010-06-25 21:14:08 +0000514 print "This script expects to reside in lldb's test directory."
515 sys.exit(-1)
516
Johnny Chen548aefd2010-10-11 22:25:46 +0000517 if rdir:
518 # Set up the LLDB_TEST environment variable appropriately, so that the
519 # individual tests can be located relatively.
520 #
521 # See also lldbtest.TestBase.setUpClass(cls).
522 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
523 os.environ["LLDB_TEST"] = os.path.join(rdir, 'test')
524 else:
525 os.environ["LLDB_TEST"] = rdir
526 else:
527 os.environ["LLDB_TEST"] = scriptPath
Johnny Chen9de4ede2010-08-31 17:42:54 +0000528 pluginPath = os.path.join(scriptPath, 'plugins')
Johnny Chen8a3c0432011-03-11 20:13:06 +0000529 pexpectPath = os.path.join(scriptPath, 'pexpect-2.4')
Johnny Chen58f93922010-06-29 23:10:39 +0000530
Johnny Chen8a3c0432011-03-11 20:13:06 +0000531 # Append script dir, plugin dir, and pexpect dir to the sys.path.
Johnny Chenaf149a02010-09-16 17:11:30 +0000532 sys.path.append(scriptPath)
533 sys.path.append(pluginPath)
Johnny Chen8a3c0432011-03-11 20:13:06 +0000534 sys.path.append(pexpectPath)
Johnny Chenaf149a02010-09-16 17:11:30 +0000535
Johnny Chen26901c82011-03-11 19:47:23 +0000536 # This is our base name component.
Johnny Chena1affab2010-07-03 03:41:59 +0000537 base = os.path.abspath(os.path.join(scriptPath, os.pardir))
Johnny Chen6a564a42011-02-15 18:50:19 +0000538
Johnny Chen26901c82011-03-11 19:47:23 +0000539 # These are for xcode build directories.
Johnny Chen6a564a42011-02-15 18:50:19 +0000540 xcode3_build_dir = ['build']
541 xcode4_build_dir = ['build', 'lldb', 'Build', 'Products']
542 dbg = ['Debug']
543 rel = ['Release']
544 bai = ['BuildAndIntegration']
545 python_resource_dir = ['LLDB.framework', 'Resources', 'Python']
Johnny Chen26901c82011-03-11 19:47:23 +0000546
547 # Some of the tests can invoke the 'lldb' command directly.
548 # We'll try to locate the appropriate executable right here.
549
550 executable = ['lldb']
551 dbgExec = os.path.join(base, *(xcode3_build_dir + dbg + executable))
552 dbgExec2 = os.path.join(base, *(xcode4_build_dir + dbg + executable))
553 relExec = os.path.join(base, *(xcode3_build_dir + rel + executable))
554 relExec2 = os.path.join(base, *(xcode4_build_dir + rel + executable))
555 baiExec = os.path.join(base, *(xcode3_build_dir + bai + executable))
556 baiExec2 = os.path.join(base, *(xcode4_build_dir + bai + executable))
557
558 lldbExec = None
559 if is_exe(dbgExec):
560 lldbExec = dbgExec
561 elif is_exe(dbgExec2):
562 lldbExec = dbgExec2
563 elif is_exe(relExec):
564 lldbExec = relExec
565 elif is_exe(relExec2):
566 lldbExec = relExec2
567 elif is_exe(baiExec):
568 lldbExec = baiExec
569 elif is_exe(baiExec2):
570 lldbExec = baiExec2
571
572 if not lldbExec:
573 lldbExec = which('lldb')
574
575 if not lldbExec:
576 print "The 'lldb' executable cannot be located. Some of the tests may not be run as a result."
577 else:
578 os.environ["LLDB_EXEC"] = lldbExec
Johnny Chend7931462011-03-17 00:38:22 +0000579 #print "The 'lldb' executable path is", lldbExec
580 os.system('%s -v' % lldbExec)
581
582 os.system('svn info %s' % base)
Johnny Chen26901c82011-03-11 19:47:23 +0000583
584 global ignore
585
586 # The '-i' option is used to skip looking for lldb.py in the build tree.
587 if ignore:
588 return
589
Johnny Chen6a564a42011-02-15 18:50:19 +0000590 dbgPath = os.path.join(base, *(xcode3_build_dir + dbg + python_resource_dir))
591 dbgPath2 = os.path.join(base, *(xcode4_build_dir + dbg + python_resource_dir))
592 relPath = os.path.join(base, *(xcode3_build_dir + rel + python_resource_dir))
593 relPath2 = os.path.join(base, *(xcode4_build_dir + rel + python_resource_dir))
594 baiPath = os.path.join(base, *(xcode3_build_dir + bai + python_resource_dir))
595 baiPath2 = os.path.join(base, *(xcode4_build_dir + bai + python_resource_dir))
Johnny Chen9707bb62010-06-25 21:14:08 +0000596
597 lldbPath = None
598 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
599 lldbPath = dbgPath
Greg Claytond9846b02011-02-14 21:17:06 +0000600 elif os.path.isfile(os.path.join(dbgPath2, 'lldb.py')):
601 lldbPath = dbgPath2
Johnny Chen9707bb62010-06-25 21:14:08 +0000602 elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
603 lldbPath = relPath
Greg Claytond9846b02011-02-14 21:17:06 +0000604 elif os.path.isfile(os.path.join(relPath2, 'lldb.py')):
605 lldbPath = relPath2
Johnny Chenc202c462010-09-15 18:11:19 +0000606 elif os.path.isfile(os.path.join(baiPath, 'lldb.py')):
607 lldbPath = baiPath
Greg Claytond9846b02011-02-14 21:17:06 +0000608 elif os.path.isfile(os.path.join(baiPath2, 'lldb.py')):
609 lldbPath = baiPath2
Johnny Chen9707bb62010-06-25 21:14:08 +0000610
611 if not lldbPath:
Johnny Chenc202c462010-09-15 18:11:19 +0000612 print 'This script requires lldb.py to be in either ' + dbgPath + ',',
613 print relPath + ', or ' + baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000614 sys.exit(-1)
615
Johnny Chenaf149a02010-09-16 17:11:30 +0000616 # This is to locate the lldb.py module. Insert it right after sys.path[0].
617 sys.path[1:1] = [lldbPath]
Johnny Chen50bc6382011-01-29 01:16:52 +0000618 if dumpSysPath:
619 print "sys.path:", sys.path
Johnny Chen9707bb62010-06-25 21:14:08 +0000620
Johnny Chen9707bb62010-06-25 21:14:08 +0000621
Johnny Chencd0279d2010-09-20 18:07:50 +0000622def doDelay(delta):
623 """Delaying startup for delta-seconds to facilitate debugger attachment."""
624 def alarm_handler(*args):
625 raise Exception("timeout")
626
627 signal.signal(signal.SIGALRM, alarm_handler)
628 signal.alarm(delta)
629 sys.stdout.write("pid=%d\n" % os.getpid())
630 sys.stdout.write("Enter RET to proceed (or timeout after %d seconds):" %
631 delta)
632 sys.stdout.flush()
633 try:
634 text = sys.stdin.readline()
635 except:
636 text = ""
637 signal.alarm(0)
638 sys.stdout.write("proceeding...\n")
639 pass
640
641
Johnny Chen9707bb62010-06-25 21:14:08 +0000642def visit(prefix, dir, names):
643 """Visitor function for os.path.walk(path, visit, arg)."""
644
645 global suite
Johnny Chen7c52ff12010-09-27 23:29:54 +0000646 global regexp
Johnny Chenb62436b2010-10-06 20:40:56 +0000647 global filterspec
648 global fs4all
Johnny Chen9707bb62010-06-25 21:14:08 +0000649
650 for name in names:
651 if os.path.isdir(os.path.join(dir, name)):
652 continue
653
654 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
Johnny Chen7c52ff12010-09-27 23:29:54 +0000655 # Try to match the regexp pattern, if specified.
656 if regexp:
657 import re
658 if re.search(regexp, name):
659 #print "Filename: '%s' matches pattern: '%s'" % (name, regexp)
660 pass
661 else:
662 #print "Filename: '%s' does not match pattern: '%s'" % (name, regexp)
663 continue
664
Johnny Chen953864a2010-10-12 21:35:54 +0000665 # We found a match for our test. Add it to the suite.
Johnny Chen79723352010-10-12 15:53:22 +0000666
667 # Update the sys.path first.
Johnny Chena85d7ee2010-06-26 00:19:32 +0000668 if not sys.path.count(dir):
Johnny Chen548aefd2010-10-11 22:25:46 +0000669 sys.path.insert(0, dir)
Johnny Chen9707bb62010-06-25 21:14:08 +0000670 base = os.path.splitext(name)[0]
Johnny Chenb62436b2010-10-06 20:40:56 +0000671
672 # Thoroughly check the filterspec against the base module and admit
673 # the (base, filterspec) combination only when it makes sense.
674 if filterspec:
675 # Optimistically set the flag to True.
676 filtered = True
677 module = __import__(base)
678 parts = filterspec.split('.')
679 obj = module
680 for part in parts:
681 try:
682 parent, obj = obj, getattr(obj, part)
683 except AttributeError:
684 # The filterspec has failed.
685 filtered = False
686 break
687 # Forgo this module if the (base, filterspec) combo is invalid
Johnny Chena224cd12010-11-08 01:21:03 +0000688 # and no '-g' option is specified
Johnny Chenb62436b2010-10-06 20:40:56 +0000689 if fs4all and not filtered:
690 continue
691
Johnny Chen953864a2010-10-12 21:35:54 +0000692 # Add either the filtered test case or the entire test class.
Johnny Chenb62436b2010-10-06 20:40:56 +0000693 if filterspec and filtered:
694 suite.addTests(
695 unittest2.defaultTestLoader.loadTestsFromName(filterspec, module))
696 else:
697 # A simple case of just the module name. Also the failover case
698 # from the filterspec branch when the (base, filterspec) combo
699 # doesn't make sense.
700 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
Johnny Chen9707bb62010-06-25 21:14:08 +0000701
702
Johnny Chencd0279d2010-09-20 18:07:50 +0000703def lldbLoggings():
704 """Check and do lldb loggings if necessary."""
705
706 # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
707 # defined. Use ${LLDB_LOG} to specify the log file.
708 ci = lldb.DBG.GetCommandInterpreter()
709 res = lldb.SBCommandReturnObject()
710 if ("LLDB_LOG" in os.environ):
711 if ("LLDB_LOG_OPTION" in os.environ):
712 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
713 else:
Johnny Chen8fd886c2010-12-08 01:25:21 +0000714 lldb_log_option = "event process expr state api"
Johnny Chencd0279d2010-09-20 18:07:50 +0000715 ci.HandleCommand(
Greg Clayton940b1032011-02-23 00:35:02 +0000716 "log enable -n -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
Johnny Chencd0279d2010-09-20 18:07:50 +0000717 res)
718 if not res.Succeeded():
719 raise Exception('log enable failed (check LLDB_LOG env variable.')
720 # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
721 # Use ${GDB_REMOTE_LOG} to specify the log file.
722 if ("GDB_REMOTE_LOG" in os.environ):
723 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
724 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
725 else:
Johnny Chen7ab8c852010-12-02 18:35:13 +0000726 gdb_remote_log_option = "packets process"
Johnny Chencd0279d2010-09-20 18:07:50 +0000727 ci.HandleCommand(
Greg Clayton940b1032011-02-23 00:35:02 +0000728 "log enable -n -f " + os.environ["GDB_REMOTE_LOG"] + " process.gdb-remote "
Johnny Chencd0279d2010-09-20 18:07:50 +0000729 + gdb_remote_log_option,
730 res)
731 if not res.Succeeded():
732 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.')
733
Johnny Chen067022b2011-01-19 19:31:46 +0000734def getMyCommandLine():
735 import subprocess
736 ps = subprocess.Popen(['ps', '-o', "command=CMD", str(os.getpid())], stdout=subprocess.PIPE).communicate()[0]
737 lines = ps.split('\n')
738 cmd_line = lines[1]
739 return cmd_line
Johnny Chencd0279d2010-09-20 18:07:50 +0000740
Johnny Chend96b5682010-11-05 17:30:53 +0000741# ======================================== #
Johnny Chencd0279d2010-09-20 18:07:50 +0000742# #
743# Execution of the test driver starts here #
744# #
Johnny Chend96b5682010-11-05 17:30:53 +0000745# ======================================== #
Johnny Chencd0279d2010-09-20 18:07:50 +0000746
Johnny Chen9707bb62010-06-25 21:14:08 +0000747#
Johnny Chenaf149a02010-09-16 17:11:30 +0000748# Start the actions by first parsing the options while setting up the test
749# directories, followed by setting up the search paths for lldb utilities;
750# then, we walk the directory trees and collect the tests into our test suite.
Johnny Chen9707bb62010-06-25 21:14:08 +0000751#
Johnny Chenaf149a02010-09-16 17:11:30 +0000752parseOptionsAndInitTestdirs()
Johnny Chen9707bb62010-06-25 21:14:08 +0000753setupSysPath()
Johnny Chen91960d32010-09-08 20:56:16 +0000754
755#
756# If '-d' is specified, do a delay of 10 seconds for the debugger to attach.
757#
758if delay:
Johnny Chencd0279d2010-09-20 18:07:50 +0000759 doDelay(10)
Johnny Chen91960d32010-09-08 20:56:16 +0000760
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000761#
Johnny Chen41998192010-10-01 22:59:49 +0000762# If '-l' is specified, do not skip the long running tests.
763if not skipLongRunningTest:
764 os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
765
766#
Johnny Chen79723352010-10-12 15:53:22 +0000767# Walk through the testdirs while collecting tests.
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000768#
Johnny Chen9707bb62010-06-25 21:14:08 +0000769for testdir in testdirs:
770 os.path.walk(testdir, visit, 'Test')
771
Johnny Chenb40056b2010-09-21 00:09:27 +0000772#
Johnny Chen9707bb62010-06-25 21:14:08 +0000773# Now that we have loaded all the test cases, run the whole test suite.
Johnny Chenb40056b2010-09-21 00:09:27 +0000774#
Johnny Chencd0279d2010-09-20 18:07:50 +0000775
Johnny Chen1bfbd412010-06-29 19:44:16 +0000776# For the time being, let's bracket the test runner within the
777# lldb.SBDebugger.Initialize()/Terminate() pair.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000778import lldb, atexit
Johnny Chen6b6f5ba2010-10-14 16:36:49 +0000779# Update: the act of importing lldb now executes lldb.SBDebugger.Initialize(),
780# there's no need to call it a second time.
781#lldb.SBDebugger.Initialize()
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000782atexit.register(lambda: lldb.SBDebugger.Terminate())
Johnny Chen1bfbd412010-06-29 19:44:16 +0000783
Johnny Chen909e5a62010-07-01 22:52:57 +0000784# Create a singleton SBDebugger in the lldb namespace.
785lldb.DBG = lldb.SBDebugger.Create()
786
Johnny Chen4f93bf12010-12-10 00:51:23 +0000787# Put the blacklist in the lldb namespace, to be used by lldb.TestBase.
Johnny Chen82e6b1e2010-12-01 22:47:54 +0000788lldb.blacklist = blacklist
789
Johnny Chen4f93bf12010-12-10 00:51:23 +0000790# Put dont/just_do_python_api_test in the lldb namespace, too.
791lldb.dont_do_python_api_test = dont_do_python_api_test
792lldb.just_do_python_api_test = just_do_python_api_test
793
Johnny Chencd0279d2010-09-20 18:07:50 +0000794# Turn on lldb loggings if necessary.
795lldbLoggings()
Johnny Chen909e5a62010-07-01 22:52:57 +0000796
Johnny Chen7987ac92010-08-09 20:40:52 +0000797# Install the control-c handler.
798unittest2.signals.installHandler()
799
Johnny Chen125fc2b2010-10-21 16:55:35 +0000800# If sdir_name is not specified through the '-s sdir_name' option, get a
801# timestamp string and export it as LLDB_SESSION_DIR environment var. This will
802# be used when/if we want to dump the session info of individual test cases
803# later on.
Johnny Chence681462010-10-19 00:25:01 +0000804#
805# See also TestBase.dumpSessionInfo() in lldbtest.py.
Johnny Chen125fc2b2010-10-21 16:55:35 +0000806if not sdir_name:
807 import datetime
Johnny Chen41fae812010-10-29 22:26:38 +0000808 # The windows platforms don't like ':' in the pathname.
Johnny Chen76bd0102010-10-28 16:32:13 +0000809 timestamp = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S")
Johnny Chen125fc2b2010-10-21 16:55:35 +0000810 sdir_name = timestamp
811os.environ["LLDB_SESSION_DIRNAME"] = sdir_name
Johnny Chen067022b2011-01-19 19:31:46 +0000812
Johnny Chen47c47c42010-11-09 23:42:00 +0000813sys.stderr.write("\nSession logs for test failures/errors will go into directory '%s'\n" % sdir_name)
Johnny Chen067022b2011-01-19 19:31:46 +0000814sys.stderr.write("Command invoked: %s\n" % getMyCommandLine())
Johnny Chence681462010-10-19 00:25:01 +0000815
Johnny Chenb40056b2010-09-21 00:09:27 +0000816#
817# Invoke the default TextTestRunner to run the test suite, possibly iterating
818# over different configurations.
819#
820
Johnny Chenb40056b2010-09-21 00:09:27 +0000821iterArchs = False
Johnny Chenf032d902010-09-21 00:16:09 +0000822iterCompilers = False
Johnny Chenb40056b2010-09-21 00:09:27 +0000823
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000824if not archs and "archs" in config:
Johnny Chenb40056b2010-09-21 00:09:27 +0000825 archs = config["archs"]
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000826
827if isinstance(archs, list) and len(archs) >= 1:
828 iterArchs = True
829
830if not compilers and "compilers" in config:
Johnny Chenb40056b2010-09-21 00:09:27 +0000831 compilers = config["compilers"]
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000832
833if isinstance(compilers, list) and len(compilers) >= 1:
834 iterCompilers = True
Johnny Chenb40056b2010-09-21 00:09:27 +0000835
Johnny Chen953864a2010-10-12 21:35:54 +0000836# Make a shallow copy of sys.path, we need to manipulate the search paths later.
837# This is only necessary if we are relocated and with different configurations.
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000838if rdir:
Johnny Chen953864a2010-10-12 21:35:54 +0000839 old_sys_path = sys.path[:]
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000840# If we iterate on archs or compilers, there is a chance we want to split stderr/stdout.
841if iterArchs or iterCompilers:
Johnny Chen953864a2010-10-12 21:35:54 +0000842 old_stderr = sys.stderr
843 old_stdout = sys.stdout
844 new_stderr = None
845 new_stdout = None
846
Johnny Chend96b5682010-11-05 17:30:53 +0000847# Iterating over all possible architecture and compiler combinations.
Johnny Chenb40056b2010-09-21 00:09:27 +0000848for ia in range(len(archs) if iterArchs else 1):
849 archConfig = ""
850 if iterArchs:
Johnny Chen18a921f2010-09-30 17:11:58 +0000851 os.environ["ARCH"] = archs[ia]
Johnny Chenb40056b2010-09-21 00:09:27 +0000852 archConfig = "arch=%s" % archs[ia]
853 for ic in range(len(compilers) if iterCompilers else 1):
854 if iterCompilers:
Johnny Chen18a921f2010-09-30 17:11:58 +0000855 os.environ["CC"] = compilers[ic]
Johnny Chenb40056b2010-09-21 00:09:27 +0000856 configString = "%s compiler=%s" % (archConfig, compilers[ic])
857 else:
858 configString = archConfig
859
Johnny Chenb40056b2010-09-21 00:09:27 +0000860 if iterArchs or iterCompilers:
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000861 # Translate ' ' to '-' for pathname component.
862 from string import maketrans
863 tbl = maketrans(' ', '-')
864 configPostfix = configString.translate(tbl)
865
866 # Check whether we need to split stderr/stdout into configuration
867 # specific files.
868 if old_stderr.name != '<stderr>' and config.get('split_stderr'):
869 if new_stderr:
870 new_stderr.close()
871 new_stderr = open("%s.%s" % (old_stderr.name, configPostfix), "w")
872 sys.stderr = new_stderr
873 if old_stdout.name != '<stdout>' and config.get('split_stdout'):
874 if new_stdout:
875 new_stdout.close()
876 new_stdout = open("%s.%s" % (old_stdout.name, configPostfix), "w")
877 sys.stdout = new_stdout
878
Johnny Chen953864a2010-10-12 21:35:54 +0000879 # If we specified a relocated directory to run the test suite, do
880 # the extra housekeeping to copy the testdirs to a configStringified
881 # directory and to update sys.path before invoking the test runner.
882 # The purpose is to separate the configuration-specific directories
883 # from each other.
884 if rdir:
Johnny Chen953864a2010-10-12 21:35:54 +0000885 from shutil import copytree, ignore_patterns
886
Johnny Chen953864a2010-10-12 21:35:54 +0000887 newrdir = "%s.%s" % (rdir, configPostfix)
888
889 # Copy the tree to a new directory with postfix name configPostfix.
890 copytree(rdir, newrdir, ignore=ignore_patterns('*.pyc', '*.o', '*.d'))
891
Johnny Chen1a4d5e72011-03-04 01:35:22 +0000892 # Update the LLDB_TEST environment variable to reflect new top
Johnny Chen953864a2010-10-12 21:35:54 +0000893 # level test directory.
894 #
895 # See also lldbtest.TestBase.setUpClass(cls).
896 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
897 os.environ["LLDB_TEST"] = os.path.join(newrdir, 'test')
898 else:
899 os.environ["LLDB_TEST"] = newrdir
900
901 # And update the Python search paths for modules.
902 sys.path = [x.replace(rdir, newrdir, 1) for x in old_sys_path]
903
904 # Output the configuration.
Johnny Chenb40056b2010-09-21 00:09:27 +0000905 sys.stderr.write("\nConfiguration: " + configString + "\n")
Johnny Chen953864a2010-10-12 21:35:54 +0000906
907 #print "sys.stderr name is", sys.stderr.name
908 #print "sys.stdout name is", sys.stdout.name
909
910 # First, write out the number of collected test cases.
911 sys.stderr.write(separator + "\n")
912 sys.stderr.write("Collected %d test%s\n\n"
913 % (suite.countTestCases(),
914 suite.countTestCases() != 1 and "s" or ""))
915
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000916 class LLDBTestResult(unittest2.TextTestResult):
917 """
Johnny Chen26be4532010-11-09 23:56:14 +0000918 Enforce a singleton pattern to allow introspection of test progress.
919
920 Overwrite addError(), addFailure(), and addExpectedFailure() methods
921 to enable each test instance to track its failure/error status. It
922 is used in the LLDB test framework to emit detailed trace messages
923 to a log file for easier human inspection of test failres/errors.
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000924 """
925 __singleton__ = None
Johnny Chen360dd372010-11-29 17:50:10 +0000926 __ignore_singleton__ = False
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000927
928 def __init__(self, *args):
Johnny Chen360dd372010-11-29 17:50:10 +0000929 if not LLDBTestResult.__ignore_singleton__ and LLDBTestResult.__singleton__:
Johnny Chend2acdb32010-11-16 22:42:58 +0000930 raise Exception("LLDBTestResult instantiated more than once")
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000931 super(LLDBTestResult, self).__init__(*args)
932 LLDBTestResult.__singleton__ = self
933 # Now put this singleton into the lldb module namespace.
934 lldb.test_result = self
Johnny Chen810042e2011-01-05 20:24:11 +0000935 # Computes the format string for displaying the counter.
936 global suite
937 counterWidth = len(str(suite.countTestCases()))
938 self.fmt = "%" + str(counterWidth) + "d: "
Johnny Chenc87fd492011-01-05 22:50:11 +0000939 self.indentation = ' ' * (counterWidth + 2)
Johnny Chen810042e2011-01-05 20:24:11 +0000940 # This counts from 1 .. suite.countTestCases().
941 self.counter = 0
942
Johnny Chenc87fd492011-01-05 22:50:11 +0000943 def getDescription(self, test):
944 doc_first_line = test.shortDescription()
945 if self.descriptions and doc_first_line:
946 return '\n'.join((str(test), self.indentation + doc_first_line))
947 else:
948 return str(test)
949
Johnny Chen810042e2011-01-05 20:24:11 +0000950 def startTest(self, test):
951 self.counter += 1
952 if self.showAll:
953 self.stream.write(self.fmt % self.counter)
954 super(LLDBTestResult, self).startTest(test)
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000955
Johnny Chence681462010-10-19 00:25:01 +0000956 def addError(self, test, err):
Johnny Chen63c2cba2010-10-29 22:20:36 +0000957 global sdir_has_content
958 sdir_has_content = True
Johnny Chence681462010-10-19 00:25:01 +0000959 super(LLDBTestResult, self).addError(test, err)
960 method = getattr(test, "markError", None)
961 if method:
962 method()
963
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000964 def addFailure(self, test, err):
Johnny Chen63c2cba2010-10-29 22:20:36 +0000965 global sdir_has_content
966 sdir_has_content = True
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000967 super(LLDBTestResult, self).addFailure(test, err)
968 method = getattr(test, "markFailure", None)
969 if method:
970 method()
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000971
Johnny Chendd2bb2c2010-11-03 18:17:03 +0000972 def addExpectedFailure(self, test, err):
973 global sdir_has_content
974 sdir_has_content = True
975 super(LLDBTestResult, self).addExpectedFailure(test, err)
976 method = getattr(test, "markExpectedFailure", None)
977 if method:
978 method()
979
Johnny Chen26be4532010-11-09 23:56:14 +0000980 # Invoke the test runner.
Johnny Chend2acdb32010-11-16 22:42:58 +0000981 if count == 1:
Johnny Chen7d6d8442010-12-03 19:59:35 +0000982 result = unittest2.TextTestRunner(stream=sys.stderr,
983 verbosity=verbose,
984 failfast=failfast,
Johnny Chend2acdb32010-11-16 22:42:58 +0000985 resultclass=LLDBTestResult).run(suite)
986 else:
Johnny Chend6e7ca22010-11-29 17:52:43 +0000987 # We are invoking the same test suite more than once. In this case,
988 # mark __ignore_singleton__ flag as True so the signleton pattern is
989 # not enforced.
Johnny Chen360dd372010-11-29 17:50:10 +0000990 LLDBTestResult.__ignore_singleton__ = True
Johnny Chend2acdb32010-11-16 22:42:58 +0000991 for i in range(count):
Johnny Chen7d6d8442010-12-03 19:59:35 +0000992 result = unittest2.TextTestRunner(stream=sys.stderr,
993 verbosity=verbose,
994 failfast=failfast,
Johnny Chen360dd372010-11-29 17:50:10 +0000995 resultclass=LLDBTestResult).run(suite)
Johnny Chenb40056b2010-09-21 00:09:27 +0000996
Johnny Chen1bfbd412010-06-29 19:44:16 +0000997
Johnny Chen63c2cba2010-10-29 22:20:36 +0000998if sdir_has_content:
Johnny Chen47c47c42010-11-09 23:42:00 +0000999 sys.stderr.write("Session logs for test failures/errors can be found in directory '%s'\n" % sdir_name)
Johnny Chen63c2cba2010-10-29 22:20:36 +00001000
Johnny Chencd0279d2010-09-20 18:07:50 +00001001# Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
1002# This should not be necessary now.
Johnny Chen83f6e512010-08-13 22:58:44 +00001003if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
1004 import subprocess
1005 print "Terminating Test suite..."
1006 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
1007
Johnny Chen01f2a6a2010-08-10 20:23:55 +00001008# Exiting.
1009sys.exit(not result.wasSuccessful)