blob: dfd12cce1b82a9454966017b2cd5b628e1351b20 [file] [log] [blame]
Johnny Chenbf6ffa32010-07-03 03:41:59 +00001"""
2LLDB module which provides the abstract base class of lldb test case.
3
4The concrete subclass can override lldbtest.TesBase in order to inherit the
5common behavior for unitest.TestCase.setUp/tearDown implemented in this file.
6
7The subclass should override the attribute mydir in order for the python runtime
8to locate the individual test cases when running as part of a large test suite
9or when running each test case as a separate python invocation.
10
11./dotest.py provides a test driver which sets up the environment to run the
12entire test suite. Users who want to run a test case on its own can specify the
13LLDB_TEST and PYTHONPATH environment variables, for example:
14
15$ export LLDB_TEST=$PWD
Johnny Chen8d55a342010-08-31 17:42:54 +000016$ export PYTHONPATH=/Volumes/data/lldb/svn/trunk/build/Debug/LLDB.framework/Resources/Python:$LLDB_TEST:$LLDB_TEST/plugins
Johnny Chenbf6ffa32010-07-03 03:41:59 +000017$ echo $LLDB_TEST
18/Volumes/data/lldb/svn/trunk/test
19$ echo $PYTHONPATH
Johnny Chen8d55a342010-08-31 17:42:54 +000020/Volumes/data/lldb/svn/trunk/build/Debug/LLDB.framework/Resources/Python:/Volumes/data/lldb/svn/trunk/test:/Volumes/data/lldb/svn/trunk/test/plugins
Johnny Chenbf6ffa32010-07-03 03:41:59 +000021$ python function_types/TestFunctionTypes.py
22.
23----------------------------------------------------------------------
24Ran 1 test in 0.363s
25
26OK
Johnny Chend0190a62010-08-23 17:10:44 +000027$ LLDB_COMMAND_TRACE=YES python array_types/TestArrayTypes.py
28LLDB_COMMAND_TRACE=YES python array_types/TestArrayTypes.py
29runCmd: file /Volumes/data/lldb/svn/trunk/test/array_types/a.out
30output: Current executable set to '/Volumes/data/lldb/svn/trunk/test/array_types/a.out' (x86_64).
31
32runCmd: breakpoint set -f main.c -l 42
33output: Breakpoint created: 1: file ='main.c', line = 42, locations = 1
34
35runCmd: run
36output: Launching '/Volumes/data/lldb/svn/trunk/test/array_types/a.out' (x86_64)
37
38runCmd: thread list
39output: Process 24987 state is Stopped
40 thread #1: tid = 0x2e03, pc = 0x0000000100000df4, where = a.out`main + 612 at /Volumes/data/lldb/svn/trunk/test/array_types/main.c:45, stop reason = breakpoint 1.1, queue = com.apple.main-thread
41
42runCmd: breakpoint list
43output: Current breakpoints:
441: file ='main.c', line = 42, locations = 1, resolved = 1
45 1.1: where = a.out`main + 612 at /Volumes/data/lldb/svn/trunk/test/array_types/main.c:45, address = 0x0000000100000df4, resolved, hit count = 1
46
47
48runCmd: variable list strings
49output: (char *[4]) strings = {
50 (char *) strings[0] = 0x0000000100000f0c "Hello",
51 (char *) strings[1] = 0x0000000100000f12 "Hola",
52 (char *) strings[2] = 0x0000000100000f17 "Bonjour",
53 (char *) strings[3] = 0x0000000100000f1f "Guten Tag"
54}
55
56runCmd: variable list char_16
57output: (char [16]) char_16 = {
58 (char) char_16[0] = 'H',
59 (char) char_16[1] = 'e',
60 (char) char_16[2] = 'l',
61 (char) char_16[3] = 'l',
62 (char) char_16[4] = 'o',
63 (char) char_16[5] = ' ',
64 (char) char_16[6] = 'W',
65 (char) char_16[7] = 'o',
66 (char) char_16[8] = 'r',
67 (char) char_16[9] = 'l',
68 (char) char_16[10] = 'd',
69 (char) char_16[11] = '\n',
70 (char) char_16[12] = '\0',
71 (char) char_16[13] = '\0',
72 (char) char_16[14] = '\0',
73 (char) char_16[15] = '\0'
74}
75
76runCmd: variable list ushort_matrix
77output: (unsigned short [2][3]) ushort_matrix = {
78 (unsigned short [3]) ushort_matrix[0] = {
79 (unsigned short) ushort_matrix[0][0] = 0x0001,
80 (unsigned short) ushort_matrix[0][1] = 0x0002,
81 (unsigned short) ushort_matrix[0][2] = 0x0003
82 },
83 (unsigned short [3]) ushort_matrix[1] = {
84 (unsigned short) ushort_matrix[1][0] = 0x000b,
85 (unsigned short) ushort_matrix[1][1] = 0x0016,
86 (unsigned short) ushort_matrix[1][2] = 0x0021
87 }
88}
89
90runCmd: variable list long_6
91output: (long [6]) long_6 = {
92 (long) long_6[0] = 1,
93 (long) long_6[1] = 2,
94 (long) long_6[2] = 3,
95 (long) long_6[3] = 4,
96 (long) long_6[4] = 5,
97 (long) long_6[5] = 6
98}
99
100.
101----------------------------------------------------------------------
102Ran 1 test in 0.349s
103
104OK
Johnny Chenbf6ffa32010-07-03 03:41:59 +0000105$
106"""
107
Johnny Chen8952a2d2010-08-30 21:35:00 +0000108import os, sys
109from subprocess import *
Johnny Chenf2b70232010-08-25 18:49:48 +0000110import time
Johnny Chena33a93c2010-08-30 23:08:52 +0000111import types
Johnny Chen73258832010-08-05 23:42:46 +0000112import unittest2
Johnny Chenbf6ffa32010-07-03 03:41:59 +0000113import lldb
114
Johnny Chen8d55a342010-08-31 17:42:54 +0000115if "LLDB_COMMAND_TRACE" in os.environ and os.environ["LLDB_COMMAND_TRACE"]=="YES":
116 traceAlways = True
117else:
118 traceAlways = False
119
120
Johnny Chen00778092010-08-09 22:01:17 +0000121#
122# Some commonly used assert messages.
123#
124
125CURRENT_EXECUTABLE_SET = "Current executable set successfully"
126
Johnny Chen5ee88192010-08-27 23:47:36 +0000127RUN_SUCCEEDED = "Process is launched successfully"
Johnny Chen00778092010-08-09 22:01:17 +0000128
Johnny Chen17941842010-08-09 23:44:24 +0000129RUN_COMPLETED = "Process exited successfully"
Johnny Chen00778092010-08-09 22:01:17 +0000130
Johnny Chen17941842010-08-09 23:44:24 +0000131BREAKPOINT_CREATED = "Breakpoint created successfully"
132
Johnny Chene76896c2010-08-17 21:33:31 +0000133BREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully"
134
Johnny Chen17941842010-08-09 23:44:24 +0000135BREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit cout = 1"
Johnny Chen00778092010-08-09 22:01:17 +0000136
137STOPPED_DUE_TO_BREAKPOINT = "Process state is stopped due to breakpoint"
138
139STOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in"
140
Johnny Chen3c884a02010-08-24 22:07:56 +0000141DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly"
142
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000143VALID_BREAKPOINT = "Got a valid breakpoint"
144
Johnny Chen5ee88192010-08-27 23:47:36 +0000145VALID_FILESPEC = "Got a valid filespec"
146
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000147VALID_PROCESS = "Got a valid process"
148
149VALID_TARGET = "Got a valid target"
150
Johnny Chen981463d2010-08-25 19:00:04 +0000151VARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly"
Johnny Chen00778092010-08-09 22:01:17 +0000152
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000153
Johnny Chen17941842010-08-09 23:44:24 +0000154#
155# And a generic "Command '%s' returns successfully" message generator.
156#
157def CMD_MSG(command):
158 return "Command '%s' returns successfully" % (command)
159
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000160#
Johnny Chen82d404c82010-08-27 18:08:58 +0000161# Returns the enum from the input string.
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000162#
Johnny Chen82d404c82010-08-27 18:08:58 +0000163def StopReasonEnum(string):
164 if string == "Invalid":
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000165 return 0
Johnny Chen82d404c82010-08-27 18:08:58 +0000166 elif string == "None":
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000167 return 1
Johnny Chen82d404c82010-08-27 18:08:58 +0000168 elif string == "Trace":
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000169 return 2
Johnny Chen82d404c82010-08-27 18:08:58 +0000170 elif string == "Breakpoint":
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000171 return 3
Johnny Chen82d404c82010-08-27 18:08:58 +0000172 elif string == "Watchpoint":
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000173 return 4
Johnny Chen82d404c82010-08-27 18:08:58 +0000174 elif string == "Signal":
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000175 return 5
Johnny Chen82d404c82010-08-27 18:08:58 +0000176 elif string == "Exception":
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000177 return 6
Johnny Chen82d404c82010-08-27 18:08:58 +0000178 elif string == "PlanComplete":
Johnny Chen5fca8ca2010-08-26 20:04:17 +0000179 return 7
180 else:
181 raise Exception("Unknown stopReason string")
Johnny Chen17941842010-08-09 23:44:24 +0000182
Johnny Chen27c41232010-08-26 21:49:29 +0000183#
Johnny Chen82d404c82010-08-27 18:08:58 +0000184# Returns the stopReason string given an enum.
185#
186def StopReasonString(enum):
187 if enum == 0:
188 return "Invalid"
189 elif enum == 1:
190 return "None"
191 elif enum == 2:
192 return "Trace"
193 elif enum == 3:
194 return "Breakpoint"
195 elif enum == 4:
196 return "Watchpoint"
197 elif enum == 5:
198 return "Signal"
199 elif enum == 6:
200 return "Exception"
201 elif enum == 7:
202 return "PlanComplete"
203 else:
204 raise Exception("Unknown stopReason enum")
205
206#
Johnny Chen27c41232010-08-26 21:49:29 +0000207# Returns an env variable array from the os.environ map object.
208#
209def EnvArray():
210 return map(lambda k,v: k+"="+v, os.environ.keys(), os.environ.values())
211
Johnny Chen8d55a342010-08-31 17:42:54 +0000212# From 2.7's subprocess.check_output() convenience function.
213def system(*popenargs, **kwargs):
214 r"""Run command with arguments and return its output as a byte string.
215
216 If the exit code was non-zero it raises a CalledProcessError. The
217 CalledProcessError object will have the return code in the returncode
218 attribute and output in the output attribute.
219
220 The arguments are the same as for the Popen constructor. Example:
221
222 >>> check_output(["ls", "-l", "/dev/null"])
223 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
224
225 The stdout argument is not allowed as it is used internally.
226 To capture standard error in the result, use stderr=STDOUT.
227
228 >>> check_output(["/bin/sh", "-c",
229 ... "ls -l non_existent_file ; exit 0"],
230 ... stderr=STDOUT)
231 'ls: non_existent_file: No such file or directory\n'
232 """
233 if 'stdout' in kwargs:
234 raise ValueError('stdout argument not allowed, it will be overridden.')
235 process = Popen(stdout=PIPE, *popenargs, **kwargs)
236 output, unused_err = process.communicate()
237 retcode = process.poll()
238
239 if traceAlways:
240 if isinstance(popenargs, types.StringTypes):
241 args = [popenargs]
242 else:
243 args = list(popenargs)
244 print >> sys.stderr
245 print >> sys.stderr, "os command:", args
246 print >> sys.stderr, "output:", output
247 print >> sys.stderr, "error:", unused_err
248 print >> sys.stderr, "retcode:", retcode
249
250 if retcode:
251 cmd = kwargs.get("args")
252 if cmd is None:
253 cmd = popenargs[0]
254 raise CalledProcessError(retcode, cmd, output=output)
255 return output
256
Johnny Chen827edff2010-08-27 00:15:48 +0000257
Johnny Chen73258832010-08-05 23:42:46 +0000258class TestBase(unittest2.TestCase):
Johnny Chenbf6ffa32010-07-03 03:41:59 +0000259 """This LLDB abstract base class is meant to be subclassed."""
260
261 # The concrete subclass should override this attribute.
Johnny Chenf02ec122010-07-03 20:41:42 +0000262 mydir = None
Johnny Chenbf6ffa32010-07-03 03:41:59 +0000263
Johnny Chen6ca006c2010-08-16 21:28:10 +0000264 # State pertaining to the inferior process, if any.
265 runStarted = False
266
Johnny Chenf2b70232010-08-25 18:49:48 +0000267 # Maximum allowed attempts when launching the inferior process.
268 # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable.
269 maxLaunchCount = 3;
270
271 # Time to wait before the next launching attempt in second(s).
272 # Can be overridden by the LLDB_TIME_WAIT environment variable.
273 timeWait = 1.0;
274
Johnny Chenbf6ffa32010-07-03 03:41:59 +0000275 def setUp(self):
Johnny Chen9289a652010-08-07 01:13:18 +0000276 #import traceback
Johnny Chena2124952010-08-05 21:23:45 +0000277 #traceback.print_stack()
278
Johnny Chenf02ec122010-07-03 20:41:42 +0000279 # Fail fast if 'mydir' attribute is not overridden.
280 if not self.mydir or len(self.mydir) == 0:
281 raise Exception("Subclasses must override the 'mydir' attribute.")
Johnny Chenbf6ffa32010-07-03 03:41:59 +0000282 # Save old working directory.
283 self.oldcwd = os.getcwd()
284
285 # Change current working directory if ${LLDB_TEST} is defined.
286 # See also dotest.py which sets up ${LLDB_TEST}.
287 if ("LLDB_TEST" in os.environ):
288 os.chdir(os.path.join(os.environ["LLDB_TEST"], self.mydir));
289
Johnny Chenf2b70232010-08-25 18:49:48 +0000290 if "LLDB_MAX_LAUNCH_COUNT" in os.environ:
291 self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"])
292
293 if "LLDB_TIME_WAIT" in os.environ:
294 self.timeWait = float(os.environ["LLDB_TIME_WAIT"])
295
Johnny Chenbf6ffa32010-07-03 03:41:59 +0000296 # Create the debugger instance if necessary.
297 try:
298 self.dbg = lldb.DBG
Johnny Chenbf6ffa32010-07-03 03:41:59 +0000299 except AttributeError:
300 self.dbg = lldb.SBDebugger.Create()
Johnny Chenf02ec122010-07-03 20:41:42 +0000301
Johnny Chenbf6ffa32010-07-03 03:41:59 +0000302 if not self.dbg.IsValid():
303 raise Exception('Invalid debugger instance')
304
305 # We want our debugger to be synchronous.
306 self.dbg.SetAsync(False)
307
308 # Retrieve the associated command interpreter instance.
309 self.ci = self.dbg.GetCommandInterpreter()
310 if not self.ci:
311 raise Exception('Could not get the command interpreter')
312
313 # And the result object.
314 self.res = lldb.SBCommandReturnObject()
315
Johnny Chenbf6ffa32010-07-03 03:41:59 +0000316 def tearDown(self):
Johnny Chen324355b2010-08-30 23:44:39 +0000317 # Terminate the current process being debugged.
Johnny Chen6ca006c2010-08-16 21:28:10 +0000318 if self.runStarted:
Johnny Chen324355b2010-08-30 23:44:39 +0000319 self.ci.HandleCommand("process kill", self.res)
Johnny Chen6ca006c2010-08-16 21:28:10 +0000320
Johnny Chenbf6ffa32010-07-03 03:41:59 +0000321 del self.dbg
322
323 # Restore old working directory.
324 os.chdir(self.oldcwd)
Johnny Chen27f212d2010-08-19 23:26:59 +0000325
Johnny Chend0190a62010-08-23 17:10:44 +0000326 def runCmd(self, cmd, msg=None, check=True, trace=False):
Johnny Chen27f212d2010-08-19 23:26:59 +0000327 """
328 Ask the command interpreter to handle the command and then check its
329 return status.
330 """
331 # Fail fast if 'cmd' is not meaningful.
332 if not cmd or len(cmd) == 0:
333 raise Exception("Bad 'cmd' parameter encountered")
Johnny Chen5bbb88f2010-08-20 17:57:32 +0000334
Johnny Chen8d55a342010-08-31 17:42:54 +0000335 trace = (True if traceAlways else trace)
Johnny Chend0190a62010-08-23 17:10:44 +0000336
Johnny Chenf2b70232010-08-25 18:49:48 +0000337 self.runStarted = (cmd.startswith("run") or
338 cmd.startswith("process launch"))
Johnny Chen5bbb88f2010-08-20 17:57:32 +0000339
Johnny Chenf2b70232010-08-25 18:49:48 +0000340 for i in range(self.maxLaunchCount if self.runStarted else 1):
341 self.ci.HandleCommand(cmd, self.res)
Johnny Chen5bbb88f2010-08-20 17:57:32 +0000342
Johnny Chenf2b70232010-08-25 18:49:48 +0000343 if trace:
344 print >> sys.stderr, "runCmd:", cmd
345 if self.res.Succeeded():
346 print >> sys.stderr, "output:", self.res.GetOutput()
347 else:
348 print >> sys.stderr, self.res.GetError()
Johnny Chen5bbb88f2010-08-20 17:57:32 +0000349
Johnny Chenff3d01d2010-08-20 21:03:09 +0000350 if self.res.Succeeded():
Johnny Chenf2b70232010-08-25 18:49:48 +0000351 break
Johnny Chenff3d01d2010-08-20 21:03:09 +0000352 else:
Johnny Chenf2b70232010-08-25 18:49:48 +0000353 if self.runStarted:
354 # Process launch failed, wait some time before the next try.
355 time.sleep(self.timeWait)
Johnny Chen5bbb88f2010-08-20 17:57:32 +0000356
Johnny Chen27f212d2010-08-19 23:26:59 +0000357 if check:
358 self.assertTrue(self.res.Succeeded(),
359 msg if msg else CMD_MSG(cmd))
360
Johnny Chend0190a62010-08-23 17:10:44 +0000361 def expect(self, cmd, msg=None, startstr=None, substrs=None, trace=False):
Johnny Chen27f212d2010-08-19 23:26:59 +0000362 """
363 Similar to runCmd; with additional expect style output matching ability.
364
365 Ask the command interpreter to handle the command and then check its
366 return status. The 'msg' parameter specifies an informational assert
367 message. We expect the output from running the command to start with
368 'startstr' and matches the substrings contained in 'substrs'.
369 """
Johnny Chen74f26b82010-08-20 19:17:39 +0000370
Johnny Chen8d55a342010-08-31 17:42:54 +0000371 trace = (True if traceAlways else trace)
Johnny Chend0190a62010-08-23 17:10:44 +0000372
Johnny Chen74f26b82010-08-20 19:17:39 +0000373 # First run the command.
Johnny Chend0190a62010-08-23 17:10:44 +0000374 self.runCmd(cmd, trace = (True if trace else False))
Johnny Chen27f212d2010-08-19 23:26:59 +0000375
Johnny Chen74f26b82010-08-20 19:17:39 +0000376 # Then compare the output against expected strings.
Johnny Chen27f212d2010-08-19 23:26:59 +0000377 output = self.res.GetOutput()
378 matched = output.startswith(startstr) if startstr else True
Johnny Chenb145bba2010-08-20 18:25:15 +0000379
Johnny Chenc7c9fcf2010-08-24 23:48:10 +0000380 if startstr and trace:
381 print >> sys.stderr, "Expecting start string:", startstr
382 print >> sys.stderr, "Matched" if matched else "Not matched"
383 print >> sys.stderr
Johnny Chenb145bba2010-08-20 18:25:15 +0000384
Johnny Chen981463d2010-08-25 19:00:04 +0000385 if substrs and matched:
Johnny Chen27f212d2010-08-19 23:26:59 +0000386 for str in substrs:
387 matched = output.find(str) > 0
Johnny Chenc7c9fcf2010-08-24 23:48:10 +0000388 if trace:
389 print >> sys.stderr, "Expecting sub string:", str
390 print >> sys.stderr, "Matched" if matched else "Not matched"
Johnny Chen27f212d2010-08-19 23:26:59 +0000391 if not matched:
392 break
Johnny Chenc7c9fcf2010-08-24 23:48:10 +0000393 if trace:
394 print >> sys.stderr
Johnny Chen27f212d2010-08-19 23:26:59 +0000395
Johnny Chen74f26b82010-08-20 19:17:39 +0000396 self.assertTrue(matched, msg if msg else CMD_MSG(cmd))
Johnny Chen27f212d2010-08-19 23:26:59 +0000397
Johnny Chenf3c59232010-08-25 22:52:45 +0000398 def invoke(self, obj, name, trace=False):
Johnny Chen61703c92010-08-25 22:56:10 +0000399 """Use reflection to call a method dynamically with no argument."""
Johnny Chenf3c59232010-08-25 22:52:45 +0000400
Johnny Chen8d55a342010-08-31 17:42:54 +0000401 trace = (True if traceAlways else trace)
Johnny Chenf3c59232010-08-25 22:52:45 +0000402
403 method = getattr(obj, name)
404 import inspect
405 self.assertTrue(inspect.ismethod(method),
406 name + "is a method name of object: " + str(obj))
407 result = method()
Johnny Chen8d55a342010-08-31 17:42:54 +0000408 if trace:
Johnny Chenf3c59232010-08-25 22:52:45 +0000409 print str(method) + ":", result
410 return result
Johnny Chen827edff2010-08-27 00:15:48 +0000411
Johnny Chen2f1ad5e2010-08-30 22:26:48 +0000412 def buildDsym(self):
413 """Platform specific way to build binaries with dsym info."""
Johnny Chen8d55a342010-08-31 17:42:54 +0000414 module = __import__(sys.platform)
415 if not module.buildDsym():
Johnny Chen2f1ad5e2010-08-30 22:26:48 +0000416 raise Exception("Don't know how to build binary with dsym")
417
418 def buildDwarf(self):
419 """Platform specific way to build binaries with dwarf maps."""
Johnny Chen8d55a342010-08-31 17:42:54 +0000420 module = __import__(sys.platform)
421 if not module.buildDwarf():
Johnny Chen2f1ad5e2010-08-30 22:26:48 +0000422 raise Exception("Don't know how to build binary with dwarf")
423
Johnny Chen827edff2010-08-27 00:15:48 +0000424 def DebugSBValue(self, frame, val):
Johnny Chen8d55a342010-08-31 17:42:54 +0000425 """Debug print a SBValue object, if traceAlways is True."""
426 if not traceAlways:
Johnny Chen827edff2010-08-27 00:15:48 +0000427 return
428
429 err = sys.stderr
430 err.write(val.GetName() + ":\n")
431 err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n')
432 err.write('\t' + "ByteSize -> " + str(val.GetByteSize()) + '\n')
433 err.write('\t' + "NumChildren -> " + str(val.GetNumChildren()) + '\n')
434 err.write('\t' + "Value -> " + str(val.GetValue(frame)) + '\n')
435 err.write('\t' + "Summary -> " + str(val.GetSummary(frame)) + '\n')
436 err.write('\t' + "IsPtrType -> " + str(val.TypeIsPtrType()) + '\n')
437 err.write('\t' + "Location -> " + val.GetLocation(frame) + '\n')
438