blob: aae5a48fdc2eb7844108da68a079feee4624a3c8 [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 Chen58f93922010-06-29 23:10:39 +000084
Johnny Chena1affab2010-07-03 03:41:59 +000085 base = os.path.abspath(os.path.join(scriptPath, os.pardir))
Johnny Chen9707bb62010-06-25 21:14:08 +000086 dbgPath = os.path.join(base, 'build', 'Debug', 'LLDB.framework',
87 'Resources', 'Python')
88 relPath = os.path.join(base, 'build', 'Release', 'LLDB.framework',
89 'Resources', 'Python')
90
91 lldbPath = None
92 if os.path.isfile(os.path.join(dbgPath, 'lldb.py')):
93 lldbPath = dbgPath
94 elif os.path.isfile(os.path.join(relPath, 'lldb.py')):
95 lldbPath = relPath
96
97 if not lldbPath:
98 print 'This script requires lldb.py to be in either ' + dbgPath,
99 print ' or' + relPath
100 sys.exit(-1)
101
102 sys.path.append(lldbPath)
Johnny Chena1affab2010-07-03 03:41:59 +0000103 sys.path.append(scriptPath)
Johnny Chen9707bb62010-06-25 21:14:08 +0000104
105
106def initTestdirs():
107 """Initialize the list of directories containing our unittest scripts.
108
109 '-h/--help as the first option prints out usage info and exit the program.
110 """
111
112 global verbose
113 global testdirs
114
115 if len(sys.argv) == 1:
116 pass
117 elif sys.argv[1].find('-h') != -1:
118 # Print usage info and exit.
119 usage()
120 sys.exit(0)
121 else:
Johnny Chend0c24b22010-08-23 17:10:44 +0000122 # Process possible trace and/or verbose flag.
Johnny Chen9707bb62010-06-25 21:14:08 +0000123 index = 1
Johnny Chend0c24b22010-08-23 17:10:44 +0000124 for i in range(1, len(sys.argv) - 1):
125 if sys.argv[index].startswith('-t'):
126 os.environ["LLDB_COMMAND_TRACE"] = "YES"
127 index += 1
128 if sys.argv[index].startswith('-v'):
129 verbose = 2
130 index += 1
Johnny Chen9707bb62010-06-25 21:14:08 +0000131
132 # Gather all the dirs passed on the command line.
133 if len(sys.argv) > index:
134 testdirs = map(os.path.abspath, sys.argv[index:])
135
Johnny Chen9707bb62010-06-25 21:14:08 +0000136
137def visit(prefix, dir, names):
138 """Visitor function for os.path.walk(path, visit, arg)."""
139
140 global suite
141
142 for name in names:
143 if os.path.isdir(os.path.join(dir, name)):
144 continue
145
146 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix):
147 # We found a pattern match for our test case. Add it to the suite.
Johnny Chena85d7ee2010-06-26 00:19:32 +0000148 if not sys.path.count(dir):
149 sys.path.append(dir)
Johnny Chen9707bb62010-06-25 21:14:08 +0000150 base = os.path.splitext(name)[0]
Johnny Chen75e28f92010-08-05 23:42:46 +0000151 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base))
Johnny Chen9707bb62010-06-25 21:14:08 +0000152
153
154#
155# Start the actions by first setting up the module search path for lldb,
156# followed by initializing the test directories, and then walking the directory
157# trees, while collecting the tests into our test suite.
158#
159setupSysPath()
160initTestdirs()
161for testdir in testdirs:
162 os.path.walk(testdir, visit, 'Test')
163
164# Now that we have loaded all the test cases, run the whole test suite.
Johnny Chen840d8e32010-08-17 23:00:13 +0000165err.writeln(separator)
166err.writeln("Collected %d test%s" % (suite.countTestCases(),
Johnny Chen877c7e42010-08-07 00:16:07 +0000167 suite.countTestCases() != 1 and "s" or ""))
Johnny Chen840d8e32010-08-17 23:00:13 +0000168err.writeln()
Johnny Chen1bfbd412010-06-29 19:44:16 +0000169
170# For the time being, let's bracket the test runner within the
171# lldb.SBDebugger.Initialize()/Terminate() pair.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000172import lldb, atexit
Johnny Chen1bfbd412010-06-29 19:44:16 +0000173lldb.SBDebugger.Initialize()
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000174atexit.register(lambda: lldb.SBDebugger.Terminate())
Johnny Chen1bfbd412010-06-29 19:44:16 +0000175
Johnny Chen909e5a62010-07-01 22:52:57 +0000176# Create a singleton SBDebugger in the lldb namespace.
177lldb.DBG = lldb.SBDebugger.Create()
178
179# Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is
Johnny Chen1a437262010-08-16 22:37:45 +0000180# defined. Use ${LLDB_LOG} to specify the log file.
Johnny Chen909e5a62010-07-01 22:52:57 +0000181ci = lldb.DBG.GetCommandInterpreter()
182res = lldb.SBCommandReturnObject()
183if ("LLDB_LOG" in os.environ):
Johnny Chen4e6c8882010-08-17 21:36:09 +0000184 if ("LLDB_LOG_OPTION" in os.environ):
185 lldb_log_option = os.environ["LLDB_LOG_OPTION"]
186 else:
187 lldb_log_option = "event process"
Johnny Chen909e5a62010-07-01 22:52:57 +0000188 ci.HandleCommand(
Johnny Chen4e6c8882010-08-17 21:36:09 +0000189 "log enable -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option,
190 res)
Johnny Chen797674b2010-07-02 20:35:23 +0000191 if not res.Succeeded():
Johnny Chen4e6c8882010-08-17 21:36:09 +0000192 raise Exception('log enable failed (check LLDB_LOG env variable.')
Johnny Chen1a437262010-08-16 22:37:45 +0000193# Ditto for gdb-remote logging if ${LLDB_LOG} environment variable is defined.
194# Use ${GDB_REMOTE_LOG} to specify the log file.
195if ("GDB_REMOTE_LOG" in os.environ):
Johnny Chen4e6c8882010-08-17 21:36:09 +0000196 if ("GDB_REMOTE_LOG_OPTION" in os.environ):
197 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"]
198 else:
199 gdb_remote_log_option = "packets"
Johnny Chen1a437262010-08-16 22:37:45 +0000200 ci.HandleCommand(
Johnny Chen4e6c8882010-08-17 21:36:09 +0000201 "log enable -f " + os.environ["GDB_REMOTE_LOG"] + " process.gdb-remote "
202 + gdb_remote_log_option,
203 res)
Johnny Chen1a437262010-08-16 22:37:45 +0000204 if not res.Succeeded():
Johnny Chen4e6c8882010-08-17 21:36:09 +0000205 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.')
Johnny Chen909e5a62010-07-01 22:52:57 +0000206
Johnny Chen7987ac92010-08-09 20:40:52 +0000207# Install the control-c handler.
208unittest2.signals.installHandler()
209
210# Invoke the default TextTestRunner to run the test suite.
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000211result = unittest2.TextTestRunner(verbosity=verbose).run(suite)
Johnny Chen1bfbd412010-06-29 19:44:16 +0000212
Johnny Chen83f6e512010-08-13 22:58:44 +0000213if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ):
214 import subprocess
215 print "Terminating Test suite..."
216 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())])
217
Johnny Chen01f2a6a2010-08-10 20:23:55 +0000218# Exiting.
219sys.exit(not result.wasSuccessful)