blob: 482d5af7880b9a60fcd270cbc1cd8a08141e34ce [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.
15"""
16
17import os
18import sys
Johnny Chen16b97472010-06-29 23:17:15 +000019import time
Johnny Chen75e28f92010-08-05 23:42:46 +000020import unittest2
Johnny Chen9707bb62010-06-25 21:14:08 +000021
Johnny Chen877c7e42010-08-07 00:16:07 +000022class _WritelnDecorator(object):
23 """Used to decorate file-like objects with a handy 'writeln' method"""
24 def __init__(self,stream):
25 self.stream = stream
26
27 def __getattr__(self, attr):
28 if attr in ('stream', '__getstate__'):
29 raise AttributeError(attr)
30 return getattr(self.stream,attr)
31
32 def writeln(self, arg=None):
33 if arg:
34 self.write(arg)
35 self.write('\n') # text-mode streams translate to \r\n if needed
36
Johnny Chen9707bb62010-06-25 21:14:08 +000037#
38# Global variables:
39#
40
41# The test suite.
Johnny Chen75e28f92010-08-05 23:42:46 +000042suite = unittest2.TestSuite()
Johnny Chen9707bb62010-06-25 21:14:08 +000043
44# Default verbosity is 0.
45verbose = 0
46
47# By default, search from the current working directory.
48testdirs = [ os.getcwd() ]
49
Johnny Chen877c7e42010-08-07 00:16:07 +000050# Separator string.
51separator = '-' * 70
52
Johnny Chen840d8e32010-08-17 23:00:13 +000053# Decorated sys.stderr for our consumption.
54err = _WritelnDecorator(sys.stderr)
Johnny Chen877c7e42010-08-07 00:16:07 +000055
Johnny Chen9707bb62010-06-25 21:14:08 +000056
57def usage():
58 print """
59Usage: dotest.py [option] [args]
60where options:
61-h : print this help message and exit (also --help)
Johnny Chend0c24b22010-08-23 17:10:44 +000062-t : trace lldb command execution and result
Johnny Chen9707bb62010-06-25 21:14:08 +000063-v : do verbose mode of unittest framework
64
65and:
66args : specify a list of directory names to search for python Test*.py scripts
67 if empty, search from the curret working directory, instead
Johnny Chen58f93922010-06-29 23:10:39 +000068
69Running of this script also sets up the LLDB_TEST environment variable so that
70individual test cases can locate their supporting files correctly.
Johnny Chen9707bb62010-06-25 21:14:08 +000071"""
72
73
74def setupSysPath():
75 """Add LLDB.framework/Resources/Python to the search paths for modules."""
76
77 # Get the directory containing the current script.
Johnny Chena1affab2010-07-03 03:41:59 +000078 scriptPath = sys.path[0]
79 if not scriptPath.endswith('test'):
Johnny Chen9707bb62010-06-25 21:14:08 +000080 print "This script expects to reside in lldb's test directory."
81 sys.exit(-1)
82
Johnny Chena1affab2010-07-03 03:41:59 +000083 os.environ["LLDB_TEST"] = scriptPath
Johnny Chen9de4ede2010-08-31 17:42:54 +000084 pluginPath = os.path.join(scriptPath, 'plugins')
Johnny Chen58f93922010-06-29 23:10:39 +000085
Johnny Chena1affab2010-07-03 03:41:59 +000086 base = os.path.abspath(os.path.join(scriptPath, os.pardir))
Johnny Chen9707bb62010-06-25 21:14:08 +000087 dbgPath = os.path.join(base, 'build', 'Debug', 'LLDB.framework',
88 'Resources', 'Python')
89 relPath = os.path.join(base, 'build', 'Release', 'LLDB.framework',
90 'Resources', 'Python')
91
92 lldbPath = None
93 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
94 lldbPath = dbgPath
95 elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
96 lldbPath = relPath
97
98 if not lldbPath:
99 print 'This script requires lldb.py to be in either ' + dbgPath,
100 print ' or' + relPath
101 sys.exit(-1)
102
103 sys.path.append(lldbPath)
Johnny Chena1affab2010-07-03 03:41:59 +0000104 sys.path.append(scriptPath)
Johnny Chen9de4ede2010-08-31 17:42:54 +0000105 sys.path.append(pluginPath)
Johnny Chen9707bb62010-06-25 21:14:08 +0000106
107
108def initTestdirs():
109 """Initialize the list of directories containing our unittest scripts.
110
111 '-h/--help as the first option prints out usage info and exit the program.
112 """
113
114 global verbose
115 global testdirs
116
117 if len(sys.argv) == 1:
118 pass
119 elif sys.argv[1].find('-h') != -1:
120 # Print usage info and exit.
121 usage()
122 sys.exit(0)
123 else:
Johnny Chend0c24b22010-08-23 17:10:44 +0000124 # Process possible trace and/or verbose flag.
Johnny Chen9707bb62010-06-25 21:14:08 +0000125 index = 1
Johnny Chend0c24b22010-08-23 17:10:44 +0000126 for i in range(1, len(sys.argv) - 1):
127 if sys.argv[index].startswith('-t'):
128 os.environ["LLDB_COMMAND_TRACE"] = "YES"
129 index += 1
130 if sys.argv[index].startswith('-v'):
131 verbose = 2
132 index += 1
Johnny Chen9707bb62010-06-25 21:14:08 +0000133
134 # Gather all the dirs passed on the command line.
135 if len(sys.argv) > index:
136 testdirs = map(os.path.abspath, sys.argv[index:])
137
Johnny Chen9707bb62010-06-25 21:14:08 +0000138
139def visit(prefix, dir, names):
140 """Visitor function for os.path.walk(path, visit, arg)."""
141
142 global suite
143
144 for name in names:
145 if os.path.isdir(os.path.join(dir, name)):
146 continue
147
148 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
149 # We found a pattern match for our test case. Add it to the suite.
Johnny Chena85d7ee2010-06-26 00:19:32 +0000150 if not sys.path.count(dir):
151 sys.path.append(dir)
Johnny Chen9707bb62010-06-25 21:14:08 +0000152 base = os.path.splitext(name)[0]
Johnny Chen75e28f92010-08-05 23:42:46 +0000153 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
Johnny Chen9707bb62010-06-25 21:14:08 +0000154
155
156#
157# Start the actions by first setting up the module search path for lldb,
158# followed by initializing the test directories, and then walking the directory
159# trees, while collecting the tests into our test suite.
160#
161setupSysPath()
162initTestdirs()
163for testdir in testdirs:
164 os.path.walk(testdir, visit, 'Test')
165
166# Now that we have loaded all the test cases, run the whole test suite.
Johnny Chen840d8e32010-08-17 23:00:13 +0000167err.writeln(separator)
168err.writeln("Collected %d test%s" % (suite.countTestCases(),
Johnny Chen877c7e42010-08-07 00:16:07 +0000169 suite.countTestCases() != 1 and "s" or ""))
Johnny Chen840d8e32010-08-17 23:00:13 +0000170err.writeln()
Johnny Chen1bfbd412010-06-29 19:44:16 +0000171
172# For the time being, let's bracket the test runner within the
173# lldb.SBDebugger.Initialize()/Terminate() pair.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000174import lldb, atexit
Johnny Chen1bfbd412010-06-29 19:44:16 +0000175lldb.SBDebugger.Initialize()
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000176atexit.register(lambda: lldb.SBDebugger.Terminate())
Johnny Chen1bfbd412010-06-29 19:44:16 +0000177
Johnny Chen909e5a62010-07-01 22:52:57 +0000178# Create a singleton SBDebugger in the lldb namespace.
179lldb.DBG = lldb.SBDebugger.Create()
180
181# Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
Johnny Chen1a437262010-08-16 22:37:45 +0000182# defined. Use ${LLDB_LOG} to specify the log file.
Johnny Chen909e5a62010-07-01 22:52:57 +0000183ci = lldb.DBG.GetCommandInterpreter()
184res = lldb.SBCommandReturnObject()
185if ("LLDB_LOG" in os.environ):
Johnny Chen4e6c8882010-08-17 21:36:09 +0000186 if ("LLDB_LOG_OPTION" in os.environ):
187 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
188 else:
189 lldb_log_option = "event process"
Johnny Chen909e5a62010-07-01 22:52:57 +0000190 ci.HandleCommand(
Johnny Chen4e6c8882010-08-17 21:36:09 +0000191 "log enable -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
192 res)
Johnny Chen797674b2010-07-02 20:35:23 +0000193 if not res.Succeeded():
Johnny Chen4e6c8882010-08-17 21:36:09 +0000194 raise Exception('log enable failed (check LLDB_LOG env variable.')
Johnny Chen1a437262010-08-16 22:37:45 +0000195# Ditto for gdb-remote logging if ${LLDB_LOG} environment variable is defined.
196# Use ${GDB_REMOTE_LOG} to specify the log file.
197if ("GDB_REMOTE_LOG" in os.environ):
Johnny Chen4e6c8882010-08-17 21:36:09 +0000198 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
199 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
200 else:
201 gdb_remote_log_option = "packets"
Johnny Chen1a437262010-08-16 22:37:45 +0000202 ci.HandleCommand(
Johnny Chen4e6c8882010-08-17 21:36:09 +0000203 "log enable -f " + os.environ["GDB_REMOTE_LOG"] + " process.gdb-remote "
204 + gdb_remote_log_option,
205 res)
Johnny Chen1a437262010-08-16 22:37:45 +0000206 if not res.Succeeded():
Johnny Chen4e6c8882010-08-17 21:36:09 +0000207 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.')
Johnny Chen909e5a62010-07-01 22:52:57 +0000208
Johnny Chen7987ac92010-08-09 20:40:52 +0000209# Install the control-c handler.
210unittest2.signals.installHandler()
211
212# Invoke the default TextTestRunner to run the test suite.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000213result = unittest2.TextTestRunner(verbosity=verbose).run(suite)
Johnny Chen1bfbd412010-06-29 19:44:16 +0000214
Johnny Chen83f6e512010-08-13 22:58:44 +0000215if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
216 import subprocess
217 print "Terminating Test suite..."
218 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
219
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000220# Exiting.
221sys.exit(not result.wasSuccessful)