blob: 5172ac57dd83a522b5bcfe93105ccd8f7bdc3b79 [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 Chen877c7e42010-08-07 00:16:07 +000026class _WritelnDecorator(object):
27 """Used to decorate file-like objects with a handy 'writeln' method"""
28 def __init__(self,stream):
29 self.stream = stream
30
31 def __getattr__(self, attr):
32 if attr in ('stream', '__getstate__'):
33 raise AttributeError(attr)
34 return getattr(self.stream,attr)
35
36 def writeln(self, arg=None):
37 if arg:
38 self.write(arg)
39 self.write('\n') # text-mode streams translate to \r\n if needed
40
Johnny Chen9707bb62010-06-25 21:14:08 +000041#
42# Global variables:
43#
44
45# The test suite.
Johnny Chen75e28f92010-08-05 23:42:46 +000046suite = unittest2.TestSuite()
Johnny Chen9707bb62010-06-25 21:14:08 +000047
Johnny Chen9fdb0a92010-09-18 00:16:47 +000048# The config file is optional.
49configFile = None
50
Johnny Chenb40056b2010-09-21 00:09:27 +000051# The dictionary as a result of sourcing configFile.
52config = {}
53
Johnny Chen91960d32010-09-08 20:56:16 +000054# Delay startup in order for the debugger to attach.
55delay = False
56
Johnny Chenb62436b2010-10-06 20:40:56 +000057# The filter (testcase.testmethod) used to admit tests into our test suite.
58filterspec = None
59
60# If '-g' is specified, the filterspec must be consulted for each test module, default to False.
61fs4all = False
62
Johnny Chenaf149a02010-09-16 17:11:30 +000063# Ignore the build search path relative to this script to locate the lldb.py module.
64ignore = False
65
Johnny Chen548aefd2010-10-11 22:25:46 +000066# By default, we skip long running test case. Use '-l' option to override.
Johnny Chen41998192010-10-01 22:59:49 +000067skipLongRunningTest = True
68
Johnny Chen7c52ff12010-09-27 23:29:54 +000069# The regular expression pattern to match against eligible filenames as our test cases.
70regexp = None
71
Johnny Chen548aefd2010-10-11 22:25:46 +000072# By default, tests are executed in place and cleanups are performed afterwards.
73# Use '-r dir' option to relocate the tests and their intermediate files to a
74# different directory and to forgo any cleanups. The directory specified must
75# not exist yet.
76rdir = None
77
Johnny Chen9707bb62010-06-25 21:14:08 +000078# Default verbosity is 0.
79verbose = 0
80
81# By default, search from the current working directory.
82testdirs = [ os.getcwd() ]
83
Johnny Chen877c7e42010-08-07 00:16:07 +000084# Separator string.
85separator = '-' * 70
86
Johnny Chen9707bb62010-06-25 21:14:08 +000087
88def usage():
89 print """
90Usage: dotest.py [option] [args]
91where options:
92-h : print this help message and exit (also --help)
Johnny Chen9fdb0a92010-09-18 00:16:47 +000093-c : read a config file specified after this option
Johnny Chenb40056b2010-09-21 00:09:27 +000094 (see also lldb-trunk/example/test/usage-config)
Johnny Chen91960d32010-09-08 20:56:16 +000095-d : delay startup for 10 seconds (in order for the debugger to attach)
Johnny Chen46be75d2010-10-11 16:19:48 +000096-f : specify a filter, which consists of the test class name, a dot, followed by
97 the test method, to admit tests into the test suite
Johnny Chenb62436b2010-10-06 20:40:56 +000098 e.g., -f 'ClassTypesTestCase.test_with_dwarf_and_python_api'
99-g : if specified, only the modules with the corect filter will be run
100 it has no effect if no '-f' option is present
101 '-f filterspec -g' can be used with '-p filename-regexp' to select only
102 the testfile.testclass.testmethod to run
Johnny Chenaf149a02010-09-16 17:11:30 +0000103-i : ignore (don't bailout) if 'lldb.py' module cannot be located in the build
104 tree relative to this script; use PYTHONPATH to locate the module
Johnny Chen41998192010-10-01 22:59:49 +0000105-l : don't skip long running test
Johnny Chen7c52ff12010-09-27 23:29:54 +0000106-p : specify a regexp filename pattern for inclusion in the test suite
Johnny Chen548aefd2010-10-11 22:25:46 +0000107-r : specify a dir to relocate the tests and their intermediate files to;
108 the directory must not exist before running this test driver;
109 no cleanup of intermediate test files is performed in this case
Johnny Chend0c24b22010-08-23 17:10:44 +0000110-t : trace lldb command execution and result
Johnny Chen9707bb62010-06-25 21:14:08 +0000111-v : do verbose mode of unittest framework
Johnny Chene47649c2010-10-07 02:04:14 +0000112-w : insert some wait time (currently 0.5 sec) between consecutive test cases
Johnny Chen9707bb62010-06-25 21:14:08 +0000113
114and:
115args : specify a list of directory names to search for python Test*.py scripts
116 if empty, search from the curret working directory, instead
Johnny Chen58f93922010-06-29 23:10:39 +0000117
118Running of this script also sets up the LLDB_TEST environment variable so that
Johnny Chenaf149a02010-09-16 17:11:30 +0000119individual test cases can locate their supporting files correctly. The script
120tries to set up Python's search paths for modules by looking at the build tree
121relative to this script. See also the '-i' option.
Johnny Chenfde69bc2010-09-14 22:01:40 +0000122
123Environment variables related to loggings:
124
125o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem
126 with a default option of 'event process' if LLDB_LOG_OPTION is not defined.
127
128o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the
129 'process.gdb-remote' subsystem with a default option of 'packets' if
130 GDB_REMOTE_LOG_OPTION is not defined.
Johnny Chen9707bb62010-06-25 21:14:08 +0000131"""
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000132 sys.exit(0)
Johnny Chen9707bb62010-06-25 21:14:08 +0000133
134
Johnny Chenaf149a02010-09-16 17:11:30 +0000135def parseOptionsAndInitTestdirs():
136 """Initialize the list of directories containing our unittest scripts.
137
138 '-h/--help as the first option prints out usage info and exit the program.
139 """
140
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000141 global configFile
Johnny Chenaf149a02010-09-16 17:11:30 +0000142 global delay
Johnny Chenb62436b2010-10-06 20:40:56 +0000143 global filterspec
144 global fs4all
Johnny Chen7c52ff12010-09-27 23:29:54 +0000145 global ignore
Johnny Chen41998192010-10-01 22:59:49 +0000146 global skipLongRunningTest
Johnny Chen7c52ff12010-09-27 23:29:54 +0000147 global regexp
Johnny Chen548aefd2010-10-11 22:25:46 +0000148 global rdir
Johnny Chenaf149a02010-09-16 17:11:30 +0000149 global verbose
150 global testdirs
151
152 if len(sys.argv) == 1:
153 return
154
155 # Process possible trace and/or verbose flag, among other things.
156 index = 1
Johnny Chence2212c2010-10-07 15:41:55 +0000157 while index < len(sys.argv):
Johnny Chenaf149a02010-09-16 17:11:30 +0000158 if not sys.argv[index].startswith('-'):
159 # End of option processing.
160 break
161
162 if sys.argv[index].find('-h') != -1:
163 usage()
Johnny Chen9fdb0a92010-09-18 00:16:47 +0000164 elif sys.argv[index].startswith('-c'):
165 # Increment by 1 to fetch the config file name option argument.
166 index += 1
167 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
168 usage()
169 configFile = sys.argv[index]
170 if not os.path.isfile(configFile):
171 print "Config file:", configFile, "does not exist!"
172 usage()
173 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000174 elif sys.argv[index].startswith('-d'):
175 delay = True
176 index += 1
Johnny Chenb62436b2010-10-06 20:40:56 +0000177 elif sys.argv[index].startswith('-f'):
178 # Increment by 1 to fetch the filter spec.
179 index += 1
180 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
181 usage()
182 filterspec = sys.argv[index]
183 index += 1
184 elif sys.argv[index].startswith('-g'):
185 fs4all = True
186 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000187 elif sys.argv[index].startswith('-i'):
188 ignore = True
189 index += 1
Johnny Chen41998192010-10-01 22:59:49 +0000190 elif sys.argv[index].startswith('-l'):
191 skipLongRunningTest = False
192 index += 1
Johnny Chen7c52ff12010-09-27 23:29:54 +0000193 elif sys.argv[index].startswith('-p'):
194 # Increment by 1 to fetch the reg exp pattern argument.
195 index += 1
196 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
197 usage()
198 regexp = sys.argv[index]
199 index += 1
Johnny Chen548aefd2010-10-11 22:25:46 +0000200 elif sys.argv[index].startswith('-r'):
201 # Increment by 1 to fetch the relocated directory argument.
202 index += 1
203 if index >= len(sys.argv) or sys.argv[index].startswith('-'):
204 usage()
205 rdir = os.path.abspath(sys.argv[index])
206 if os.path.exists(rdir):
207 print "Relocated directory:", rdir, "must not exist!"
208 usage()
209 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000210 elif sys.argv[index].startswith('-t'):
211 os.environ["LLDB_COMMAND_TRACE"] = "YES"
212 index += 1
213 elif sys.argv[index].startswith('-v'):
214 verbose = 2
215 index += 1
Johnny Chene47649c2010-10-07 02:04:14 +0000216 elif sys.argv[index].startswith('-w'):
217 os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] = 'YES'
218 index += 1
Johnny Chenaf149a02010-09-16 17:11:30 +0000219 else:
220 print "Unknown option: ", sys.argv[index]
221 usage()
Johnny Chenaf149a02010-09-16 17:11:30 +0000222
223 # Gather all the dirs passed on the command line.
224 if len(sys.argv) > index:
225 testdirs = map(os.path.abspath, sys.argv[index:])
226
Johnny Chen548aefd2010-10-11 22:25:46 +0000227 # If '-r dir' is specified, the tests should be run under the relocated
228 # directory. Let's copy the testdirs over.
229 if rdir:
230 from shutil import copytree, ignore_patterns
231
232 tmpdirs = []
233 for srcdir in testdirs:
234 dstdir = os.path.join(rdir, os.path.basename(srcdir))
235 # Don't copy the *.pyc and .svn stuffs.
236 copytree(srcdir, dstdir, ignore=ignore_patterns('*.pyc', '.svn'))
237 tmpdirs.append(dstdir)
238
239 # This will be our modified testdirs.
240 testdirs = tmpdirs
241
242 # With '-r dir' specified, there's no cleanup of intermediate test files.
243 os.environ["LLDB_DO_CLEANUP"] = 'NO'
244
245 # If testdirs is ['test'], the make directory has already been copied
246 # recursively and is contained within the rdir/test dir. For anything
247 # else, we would need to copy over the make directory and its contents,
248 # so that, os.listdir(rdir) looks like, for example:
249 #
250 # array_types conditional_break make
251 #
252 # where the make directory contains the Makefile.rules file.
253 if len(testdirs) != 1 or os.path.basename(testdirs[0]) != 'test':
254 # Don't copy the .svn stuffs.
255 copytree('make', os.path.join(rdir, 'make'),
256 ignore=ignore_patterns('.svn'))
257
258 #print "testdirs:", testdirs
259
Johnny Chenb40056b2010-09-21 00:09:27 +0000260 # Source the configFile if specified.
261 # The side effect, if any, will be felt from this point on. An example
262 # config file may be these simple two lines:
263 #
264 # sys.stderr = open("/tmp/lldbtest-stderr", "w")
265 # sys.stdout = open("/tmp/lldbtest-stdout", "w")
266 #
267 # which will reassign the two file objects to sys.stderr and sys.stdout,
268 # respectively.
269 #
270 # See also lldb-trunk/example/test/usage-config.
271 global config
272 if configFile:
273 # Pass config (a dictionary) as the locals namespace for side-effect.
274 execfile(configFile, globals(), config)
275 #print "config:", config
276 #print "sys.stderr:", sys.stderr
277 #print "sys.stdout:", sys.stdout
278
Johnny Chenaf149a02010-09-16 17:11:30 +0000279
Johnny Chen9707bb62010-06-25 21:14:08 +0000280def setupSysPath():
281 """Add LLDB.framework/Resources/Python to the search paths for modules."""
282
Johnny Chen548aefd2010-10-11 22:25:46 +0000283 global rdir
284 global testdirs
285
Johnny Chen9707bb62010-06-25 21:14:08 +0000286 # Get the directory containing the current script.
Johnny Chena1affab2010-07-03 03:41:59 +0000287 scriptPath = sys.path[0]
288 if not scriptPath.endswith('test'):
Johnny Chen9707bb62010-06-25 21:14:08 +0000289 print "This script expects to reside in lldb's test directory."
290 sys.exit(-1)
291
Johnny Chen548aefd2010-10-11 22:25:46 +0000292 if rdir:
293 # Set up the LLDB_TEST environment variable appropriately, so that the
294 # individual tests can be located relatively.
295 #
296 # See also lldbtest.TestBase.setUpClass(cls).
297 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
298 os.environ["LLDB_TEST"] = os.path.join(rdir, 'test')
299 else:
300 os.environ["LLDB_TEST"] = rdir
301 else:
302 os.environ["LLDB_TEST"] = scriptPath
Johnny Chen9de4ede2010-08-31 17:42:54 +0000303 pluginPath = os.path.join(scriptPath, 'plugins')
Johnny Chen58f93922010-06-29 23:10:39 +0000304
Johnny Chenaf149a02010-09-16 17:11:30 +0000305 # Append script dir and plugin dir to the sys.path.
306 sys.path.append(scriptPath)
307 sys.path.append(pluginPath)
308
309 global ignore
310
311 # The '-i' option is used to skip looking for lldb.py in the build tree.
312 if ignore:
313 return
314
Johnny Chena1affab2010-07-03 03:41:59 +0000315 base = os.path.abspath(os.path.join(scriptPath, os.pardir))
Johnny Chen9707bb62010-06-25 21:14:08 +0000316 dbgPath = os.path.join(base, 'build', 'Debug', 'LLDB.framework',
317 'Resources', 'Python')
318 relPath = os.path.join(base, 'build', 'Release', 'LLDB.framework',
319 'Resources', 'Python')
Johnny Chenc202c462010-09-15 18:11:19 +0000320 baiPath = os.path.join(base, 'build', 'BuildAndIntegration',
321 'LLDB.framework', 'Resources', 'Python')
Johnny Chen9707bb62010-06-25 21:14:08 +0000322
323 lldbPath = None
324 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
325 lldbPath = dbgPath
326 elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
327 lldbPath = relPath
Johnny Chenc202c462010-09-15 18:11:19 +0000328 elif os.path.isfile(os.path.join(baiPath, 'lldb.py')):
329 lldbPath = baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000330
331 if not lldbPath:
Johnny Chenc202c462010-09-15 18:11:19 +0000332 print 'This script requires lldb.py to be in either ' + dbgPath + ',',
333 print relPath + ', or ' + baiPath
Johnny Chen9707bb62010-06-25 21:14:08 +0000334 sys.exit(-1)
335
Johnny Chenaf149a02010-09-16 17:11:30 +0000336 # This is to locate the lldb.py module. Insert it right after sys.path[0].
337 sys.path[1:1] = [lldbPath]
Johnny Chen9707bb62010-06-25 21:14:08 +0000338
Johnny Chen9707bb62010-06-25 21:14:08 +0000339
Johnny Chencd0279d2010-09-20 18:07:50 +0000340def doDelay(delta):
341 """Delaying startup for delta-seconds to facilitate debugger attachment."""
342 def alarm_handler(*args):
343 raise Exception("timeout")
344
345 signal.signal(signal.SIGALRM, alarm_handler)
346 signal.alarm(delta)
347 sys.stdout.write("pid=%d\n" % os.getpid())
348 sys.stdout.write("Enter RET to proceed (or timeout after %d seconds):" %
349 delta)
350 sys.stdout.flush()
351 try:
352 text = sys.stdin.readline()
353 except:
354 text = ""
355 signal.alarm(0)
356 sys.stdout.write("proceeding...\n")
357 pass
358
359
Johnny Chen9707bb62010-06-25 21:14:08 +0000360def visit(prefix, dir, names):
361 """Visitor function for os.path.walk(path, visit, arg)."""
362
363 global suite
Johnny Chen7c52ff12010-09-27 23:29:54 +0000364 global regexp
Johnny Chenb62436b2010-10-06 20:40:56 +0000365 global filterspec
366 global fs4all
Johnny Chen9707bb62010-06-25 21:14:08 +0000367
368 for name in names:
369 if os.path.isdir(os.path.join(dir, name)):
370 continue
371
372 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
Johnny Chen7c52ff12010-09-27 23:29:54 +0000373 # Try to match the regexp pattern, if specified.
374 if regexp:
375 import re
376 if re.search(regexp, name):
377 #print "Filename: '%s' matches pattern: '%s'" % (name, regexp)
378 pass
379 else:
380 #print "Filename: '%s' does not match pattern: '%s'" % (name, regexp)
381 continue
382
Johnny Chen953864a2010-10-12 21:35:54 +0000383 # We found a match for our test. Add it to the suite.
Johnny Chen79723352010-10-12 15:53:22 +0000384
385 # Update the sys.path first.
Johnny Chena85d7ee2010-06-26 00:19:32 +0000386 if not sys.path.count(dir):
Johnny Chen548aefd2010-10-11 22:25:46 +0000387 sys.path.insert(0, dir)
Johnny Chen9707bb62010-06-25 21:14:08 +0000388 base = os.path.splitext(name)[0]
Johnny Chenb62436b2010-10-06 20:40:56 +0000389
390 # Thoroughly check the filterspec against the base module and admit
391 # the (base, filterspec) combination only when it makes sense.
392 if filterspec:
393 # Optimistically set the flag to True.
394 filtered = True
395 module = __import__(base)
396 parts = filterspec.split('.')
397 obj = module
398 for part in parts:
399 try:
400 parent, obj = obj, getattr(obj, part)
401 except AttributeError:
402 # The filterspec has failed.
403 filtered = False
404 break
405 # Forgo this module if the (base, filterspec) combo is invalid
406 # and the '-g' option is present.
407 if fs4all and not filtered:
408 continue
409
Johnny Chen953864a2010-10-12 21:35:54 +0000410 # Add either the filtered test case or the entire test class.
Johnny Chenb62436b2010-10-06 20:40:56 +0000411 if filterspec and filtered:
412 suite.addTests(
413 unittest2.defaultTestLoader.loadTestsFromName(filterspec, module))
414 else:
415 # A simple case of just the module name. Also the failover case
416 # from the filterspec branch when the (base, filterspec) combo
417 # doesn't make sense.
418 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
Johnny Chen9707bb62010-06-25 21:14:08 +0000419
420
Johnny Chencd0279d2010-09-20 18:07:50 +0000421def lldbLoggings():
422 """Check and do lldb loggings if necessary."""
423
424 # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
425 # defined. Use ${LLDB_LOG} to specify the log file.
426 ci = lldb.DBG.GetCommandInterpreter()
427 res = lldb.SBCommandReturnObject()
428 if ("LLDB_LOG" in os.environ):
429 if ("LLDB_LOG_OPTION" in os.environ):
430 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
431 else:
432 lldb_log_option = "event process"
433 ci.HandleCommand(
434 "log enable -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
435 res)
436 if not res.Succeeded():
437 raise Exception('log enable failed (check LLDB_LOG env variable.')
438 # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined.
439 # Use ${GDB_REMOTE_LOG} to specify the log file.
440 if ("GDB_REMOTE_LOG" in os.environ):
441 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
442 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
443 else:
444 gdb_remote_log_option = "packets"
445 ci.HandleCommand(
446 "log enable -f " + os.environ["GDB_REMOTE_LOG"] + " process.gdb-remote "
447 + gdb_remote_log_option,
448 res)
449 if not res.Succeeded():
450 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.')
451
452
453############################################
454# #
455# Execution of the test driver starts here #
456# #
457############################################
458
Johnny Chen9707bb62010-06-25 21:14:08 +0000459#
Johnny Chenaf149a02010-09-16 17:11:30 +0000460# Start the actions by first parsing the options while setting up the test
461# directories, followed by setting up the search paths for lldb utilities;
462# then, we walk the directory trees and collect the tests into our test suite.
Johnny Chen9707bb62010-06-25 21:14:08 +0000463#
Johnny Chenaf149a02010-09-16 17:11:30 +0000464parseOptionsAndInitTestdirs()
Johnny Chen9707bb62010-06-25 21:14:08 +0000465setupSysPath()
Johnny Chen91960d32010-09-08 20:56:16 +0000466
467#
468# If '-d' is specified, do a delay of 10 seconds for the debugger to attach.
469#
470if delay:
Johnny Chencd0279d2010-09-20 18:07:50 +0000471 doDelay(10)
Johnny Chen91960d32010-09-08 20:56:16 +0000472
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000473#
Johnny Chen41998192010-10-01 22:59:49 +0000474# If '-l' is specified, do not skip the long running tests.
475if not skipLongRunningTest:
476 os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO"
477
478#
Johnny Chen79723352010-10-12 15:53:22 +0000479# Walk through the testdirs while collecting tests.
Johnny Chen49f2f7a2010-09-20 17:25:45 +0000480#
Johnny Chen9707bb62010-06-25 21:14:08 +0000481for testdir in testdirs:
482 os.path.walk(testdir, visit, 'Test')
483
Johnny Chenb40056b2010-09-21 00:09:27 +0000484#
Johnny Chen9707bb62010-06-25 21:14:08 +0000485# Now that we have loaded all the test cases, run the whole test suite.
Johnny Chenb40056b2010-09-21 00:09:27 +0000486#
Johnny Chencd0279d2010-09-20 18:07:50 +0000487
Johnny Chen1bfbd412010-06-29 19:44:16 +0000488# For the time being, let's bracket the test runner within the
489# lldb.SBDebugger.Initialize()/Terminate() pair.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000490import lldb, atexit
Johnny Chen6b6f5ba2010-10-14 16:36:49 +0000491# Update: the act of importing lldb now executes lldb.SBDebugger.Initialize(),
492# there's no need to call it a second time.
493#lldb.SBDebugger.Initialize()
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000494atexit.register(lambda: lldb.SBDebugger.Terminate())
Johnny Chen1bfbd412010-06-29 19:44:16 +0000495
Johnny Chen909e5a62010-07-01 22:52:57 +0000496# Create a singleton SBDebugger in the lldb namespace.
497lldb.DBG = lldb.SBDebugger.Create()
498
Johnny Chencd0279d2010-09-20 18:07:50 +0000499# Turn on lldb loggings if necessary.
500lldbLoggings()
Johnny Chen909e5a62010-07-01 22:52:57 +0000501
Johnny Chen7987ac92010-08-09 20:40:52 +0000502# Install the control-c handler.
503unittest2.signals.installHandler()
504
Johnny Chenb40056b2010-09-21 00:09:27 +0000505#
506# Invoke the default TextTestRunner to run the test suite, possibly iterating
507# over different configurations.
508#
509
Johnny Chenb40056b2010-09-21 00:09:27 +0000510iterArchs = False
Johnny Chenf032d902010-09-21 00:16:09 +0000511iterCompilers = False
Johnny Chenb40056b2010-09-21 00:09:27 +0000512
513from types import *
514if "archs" in config:
515 archs = config["archs"]
516 if type(archs) is ListType and len(archs) >= 1:
517 iterArchs = True
518if "compilers" in config:
519 compilers = config["compilers"]
520 if type(compilers) is ListType and len(compilers) >= 1:
521 iterCompilers = True
522
Johnny Chen953864a2010-10-12 21:35:54 +0000523# Make a shallow copy of sys.path, we need to manipulate the search paths later.
524# This is only necessary if we are relocated and with different configurations.
525if rdir and (iterArchs or iterCompilers):
526 old_sys_path = sys.path[:]
527 old_stderr = sys.stderr
528 old_stdout = sys.stdout
529 new_stderr = None
530 new_stdout = None
531
Johnny Chenb40056b2010-09-21 00:09:27 +0000532for ia in range(len(archs) if iterArchs else 1):
533 archConfig = ""
534 if iterArchs:
Johnny Chen18a921f2010-09-30 17:11:58 +0000535 os.environ["ARCH"] = archs[ia]
Johnny Chenb40056b2010-09-21 00:09:27 +0000536 archConfig = "arch=%s" % archs[ia]
537 for ic in range(len(compilers) if iterCompilers else 1):
538 if iterCompilers:
Johnny Chen18a921f2010-09-30 17:11:58 +0000539 os.environ["CC"] = compilers[ic]
Johnny Chenb40056b2010-09-21 00:09:27 +0000540 configString = "%s compiler=%s" % (archConfig, compilers[ic])
541 else:
542 configString = archConfig
543
Johnny Chenb40056b2010-09-21 00:09:27 +0000544 if iterArchs or iterCompilers:
Johnny Chen953864a2010-10-12 21:35:54 +0000545 # If we specified a relocated directory to run the test suite, do
546 # the extra housekeeping to copy the testdirs to a configStringified
547 # directory and to update sys.path before invoking the test runner.
548 # The purpose is to separate the configuration-specific directories
549 # from each other.
550 if rdir:
551 from string import maketrans
552 from shutil import copytree, ignore_patterns
553
554 # Translate ' ' to '-' for dir name.
555 tbl = maketrans(' ', '-')
556 configPostfix = configString.translate(tbl)
557 newrdir = "%s.%s" % (rdir, configPostfix)
558
559 # Copy the tree to a new directory with postfix name configPostfix.
560 copytree(rdir, newrdir, ignore=ignore_patterns('*.pyc', '*.o', '*.d'))
561
562 # Check whether we need to split stderr/stdout into configuration
563 # specific files.
564 if old_stderr.name != '<stderr>' and config.get('split_stderr'):
565 if new_stderr:
566 new_stderr.close()
567 new_stderr = open("%s.%s" % (old_stderr.name, configPostfix), "w")
568 sys.stderr = new_stderr
Johnny Chen4b6630e2010-10-12 21:50:36 +0000569 if old_stdout.name != '<stdout>' and config.get('split_stdout'):
Johnny Chen953864a2010-10-12 21:35:54 +0000570 if new_stdout:
571 new_stdout.close()
572 new_stdout = open("%s.%s" % (old_stdout.name, configPostfix), "w")
573 sys.stdout = new_stdout
574
575 # Update the LLDB_TEST environment variable to reflect new top
576 # level test directory.
577 #
578 # See also lldbtest.TestBase.setUpClass(cls).
579 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test':
580 os.environ["LLDB_TEST"] = os.path.join(newrdir, 'test')
581 else:
582 os.environ["LLDB_TEST"] = newrdir
583
584 # And update the Python search paths for modules.
585 sys.path = [x.replace(rdir, newrdir, 1) for x in old_sys_path]
586
587 # Output the configuration.
Johnny Chenb40056b2010-09-21 00:09:27 +0000588 sys.stderr.write("\nConfiguration: " + configString + "\n")
Johnny Chen953864a2010-10-12 21:35:54 +0000589
590 #print "sys.stderr name is", sys.stderr.name
591 #print "sys.stdout name is", sys.stdout.name
592
593 # First, write out the number of collected test cases.
594 sys.stderr.write(separator + "\n")
595 sys.stderr.write("Collected %d test%s\n\n"
596 % (suite.countTestCases(),
597 suite.countTestCases() != 1 and "s" or ""))
598
599 # Invoke the test runner.
Johnny Chen84a6d6f2010-10-15 01:18:29 +0000600 class LLDBTestResult(unittest2.TextTestResult):
601 """
602 Enforce a singleton pattern to allow inspection of test progress.
603 """
604 __singleton__ = None
605
606 def __init__(self, *args):
607 if LLDBTestResult.__singleton__:
608 raise "LLDBTestResult instantiated more than once"
609 super(LLDBTestResult, self).__init__(*args)
610 LLDBTestResult.__singleton__ = self
611 # Now put this singleton into the lldb module namespace.
612 lldb.test_result = self
613
614 def addFailure(self, test, err):
615 super(LLDBTestResult, self).addFailure(test, err)
616 method = getattr(test, "markFailure", None)
617 if method:
618 method()
619 setattr(test, "__failed__", True)
620
621 result = unittest2.TextTestRunner(stream=sys.stderr, verbosity=verbose,
622 resultclass=LLDBTestResult).run(suite)
Johnny Chenb40056b2010-09-21 00:09:27 +0000623
Johnny Chen1bfbd412010-06-29 19:44:16 +0000624
Johnny Chencd0279d2010-09-20 18:07:50 +0000625# Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined.
626# This should not be necessary now.
Johnny Chen83f6e512010-08-13 22:58:44 +0000627if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
628 import subprocess
629 print "Terminating Test suite..."
630 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
631
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000632# Exiting.
633sys.exit(not result.wasSuccessful)