blob: dfd12cce1b82a9454966017b2cd5b628e1351b20 [file] [log] [blame]
Johnny Chena1affab2010-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 Chen9de4ede2010-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 Chena1affab2010-07-03 03:41:59 +000017$ echo $LLDB_TEST
18/Volumes/data/lldb/svn/trunk/test
19$ echo $PYTHONPATH
Johnny Chen9de4ede2010-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 Chena1affab2010-07-03 03:41:59 +000021$ python function_types/TestFunctionTypes.py
22.
23----------------------------------------------------------------------
24Ran 1 test in 0.363s
25
26OK
Johnny Chend0c24b22010-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 Chena1affab2010-07-03 03:41:59 +0000105$
106"""
107
Johnny Chena1cc8832010-08-30 21:35:00 +0000108import os, sys
109from subprocess import *
Johnny Chen65572482010-08-25 18:49:48 +0000110import time
Johnny Chen1acaf632010-08-30 23:08:52 +0000111import types
Johnny Chen75e28f92010-08-05 23:42:46 +0000112import unittest2
Johnny Chena1affab2010-07-03 03:41:59 +0000113import lldb
114
Johnny Chen9de4ede2010-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 Chen96f08d52010-08-09 22:01:17 +0000121#
122# Some commonly used assert messages.
123#
124
125CURRENT_EXECUTABLE_SET = "Current executable set successfully"
126
Johnny Chen1bb9f9a2010-08-27 23:47:36 +0000127RUN_SUCCEEDED = "Process is launched successfully"
Johnny Chen96f08d52010-08-09 22:01:17 +0000128
Johnny Chend85dae52010-08-09 23:44:24 +0000129RUN_COMPLETED = "Process exited successfully"
Johnny Chen96f08d52010-08-09 22:01:17 +0000130
Johnny Chend85dae52010-08-09 23:44:24 +0000131BREAKPOINT_CREATED = "Breakpoint created successfully"
132
Johnny Chen9b92c6e2010-08-17 21:33:31 +0000133BREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully"
134
Johnny Chend85dae52010-08-09 23:44:24 +0000135BREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit cout = 1"
Johnny Chen96f08d52010-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 Chen4917e102010-08-24 22:07:56 +0000141DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly"
142
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000143VALID_BREAKPOINT = "Got a valid breakpoint"
144
Johnny Chen1bb9f9a2010-08-27 23:47:36 +0000145VALID_FILESPEC = "Got a valid filespec"
146
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000147VALID_PROCESS = "Got a valid process"
148
149VALID_TARGET = "Got a valid target"
150
Johnny Chen22b95b22010-08-25 19:00:04 +0000151VARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly"
Johnny Chen96f08d52010-08-09 22:01:17 +0000152
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000153
Johnny Chend85dae52010-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 Chenb4d1fff2010-08-26 20:04:17 +0000160#
Johnny Chen6264bc62010-08-27 18:08:58 +0000161# Returns the enum from the input string.
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000162#
Johnny Chen6264bc62010-08-27 18:08:58 +0000163def StopReasonEnum(string):
164 if string == "Invalid":
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000165 return 0
Johnny Chen6264bc62010-08-27 18:08:58 +0000166 elif string == "None":
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000167 return 1
Johnny Chen6264bc62010-08-27 18:08:58 +0000168 elif string == "Trace":
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000169 return 2
Johnny Chen6264bc62010-08-27 18:08:58 +0000170 elif string == "Breakpoint":
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000171 return 3
Johnny Chen6264bc62010-08-27 18:08:58 +0000172 elif string == "Watchpoint":
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000173 return 4
Johnny Chen6264bc62010-08-27 18:08:58 +0000174 elif string == "Signal":
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000175 return 5
Johnny Chen6264bc62010-08-27 18:08:58 +0000176 elif string == "Exception":
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000177 return 6
Johnny Chen6264bc62010-08-27 18:08:58 +0000178 elif string == "PlanComplete":
Johnny Chenb4d1fff2010-08-26 20:04:17 +0000179 return 7
180 else:
181 raise Exception("Unknown stopReason string")
Johnny Chend85dae52010-08-09 23:44:24 +0000182
Johnny Chenf4ce2882010-08-26 21:49:29 +0000183#
Johnny Chen6264bc62010-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 Chenf4ce2882010-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 Chen9de4ede2010-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 Chen9c10c182010-08-27 00:15:48 +0000257
Johnny Chen75e28f92010-08-05 23:42:46 +0000258class TestBase(unittest2.TestCase):
Johnny Chena1affab2010-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 Chenf8c723b2010-07-03 20:41:42 +0000262 mydir = None
Johnny Chena1affab2010-07-03 03:41:59 +0000263
Johnny Chenffde4fc2010-08-16 21:28:10 +0000264 # State pertaining to the inferior process, if any.
265 runStarted = False
266
Johnny Chen65572482010-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 Chena1affab2010-07-03 03:41:59 +0000275 def setUp(self):
Johnny Chen6ead27f2010-08-07 01:13:18 +0000276 #import traceback
Johnny Chen88f83042010-08-05 21:23:45 +0000277 #traceback.print_stack()
278
Johnny Chenf8c723b2010-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 Chena1affab2010-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 Chen65572482010-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 Chena1affab2010-07-03 03:41:59 +0000296 # Create the debugger instance if necessary.
297 try:
298 self.dbg = lldb.DBG
Johnny Chena1affab2010-07-03 03:41:59 +0000299 except AttributeError:
300 self.dbg = lldb.SBDebugger.Create()
Johnny Chenf8c723b2010-07-03 20:41:42 +0000301
Johnny Chena1affab2010-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 Chena1affab2010-07-03 03:41:59 +0000316 def tearDown(self):
Johnny Chen32caf6a2010-08-30 23:44:39 +0000317 # Terminate the current process being debugged.
Johnny Chenffde4fc2010-08-16 21:28:10 +0000318 if self.runStarted:
Johnny Chen32caf6a2010-08-30 23:44:39 +0000319 self.ci.HandleCommand("process kill", self.res)
Johnny Chenffde4fc2010-08-16 21:28:10 +0000320
Johnny Chena1affab2010-07-03 03:41:59 +0000321 del self.dbg
322
323 # Restore old working directory.
324 os.chdir(self.oldcwd)
Johnny Chen8df95eb2010-08-19 23:26:59 +0000325
Johnny Chend0c24b22010-08-23 17:10:44 +0000326 def runCmd(self, cmd, msg=None, check=True, trace=False):
Johnny Chen8df95eb2010-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 Chen4f995f02010-08-20 17:57:32 +0000334
Johnny Chen9de4ede2010-08-31 17:42:54 +0000335 trace = (True if traceAlways else trace)
Johnny Chend0c24b22010-08-23 17:10:44 +0000336
Johnny Chen65572482010-08-25 18:49:48 +0000337 self.runStarted = (cmd.startswith("run") or
338 cmd.startswith("process launch"))
Johnny Chen4f995f02010-08-20 17:57:32 +0000339
Johnny Chen65572482010-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 Chen4f995f02010-08-20 17:57:32 +0000342
Johnny Chen65572482010-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 Chen4f995f02010-08-20 17:57:32 +0000349
Johnny Chen029acae2010-08-20 21:03:09 +0000350 if self.res.Succeeded():
Johnny Chen65572482010-08-25 18:49:48 +0000351 break
Johnny Chen029acae2010-08-20 21:03:09 +0000352 else:
Johnny Chen65572482010-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 Chen4f995f02010-08-20 17:57:32 +0000356
Johnny Chen8df95eb2010-08-19 23:26:59 +0000357 if check:
358 self.assertTrue(self.res.Succeeded(),
359 msg if msg else CMD_MSG(cmd))
360
Johnny Chend0c24b22010-08-23 17:10:44 +0000361 def expect(self, cmd, msg=None, startstr=None, substrs=None, trace=False):
Johnny Chen8df95eb2010-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 Chene8b02f32010-08-20 19:17:39 +0000370
Johnny Chen9de4ede2010-08-31 17:42:54 +0000371 trace = (True if traceAlways else trace)
Johnny Chend0c24b22010-08-23 17:10:44 +0000372
Johnny Chene8b02f32010-08-20 19:17:39 +0000373 # First run the command.
Johnny Chend0c24b22010-08-23 17:10:44 +0000374 self.runCmd(cmd, trace = (True if trace else False))
Johnny Chen8df95eb2010-08-19 23:26:59 +0000375
Johnny Chene8b02f32010-08-20 19:17:39 +0000376 # Then compare the output against expected strings.
Johnny Chen8df95eb2010-08-19 23:26:59 +0000377 output = self.res.GetOutput()
378 matched = output.startswith(startstr) if startstr else True
Johnny Chenead35c82010-08-20 18:25:15 +0000379
Johnny Chen3f3fb132010-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 Chenead35c82010-08-20 18:25:15 +0000384
Johnny Chen22b95b22010-08-25 19:00:04 +0000385 if substrs and matched:
Johnny Chen8df95eb2010-08-19 23:26:59 +0000386 for str in substrs:
387 matched = output.find(str) > 0
Johnny Chen3f3fb132010-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 Chen8df95eb2010-08-19 23:26:59 +0000391 if not matched:
392 break
Johnny Chen3f3fb132010-08-24 23:48:10 +0000393 if trace:
394 print >> sys.stderr
Johnny Chen8df95eb2010-08-19 23:26:59 +0000395
Johnny Chene8b02f32010-08-20 19:17:39 +0000396 self.assertTrue(matched, msg if msg else CMD_MSG(cmd))
Johnny Chen8df95eb2010-08-19 23:26:59 +0000397
Johnny Chena8b3cdd2010-08-25 22:52:45 +0000398 def invoke(self, obj, name, trace=False):
Johnny Chend8473bc2010-08-25 22:56:10 +0000399 """Use reflection to call a method dynamically with no argument."""
Johnny Chena8b3cdd2010-08-25 22:52:45 +0000400
Johnny Chen9de4ede2010-08-31 17:42:54 +0000401 trace = (True if traceAlways else trace)
Johnny Chena8b3cdd2010-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 Chen9de4ede2010-08-31 17:42:54 +0000408 if trace:
Johnny Chena8b3cdd2010-08-25 22:52:45 +0000409 print str(method) + ":", result
410 return result
Johnny Chen9c10c182010-08-27 00:15:48 +0000411
Johnny Cheneef7a862010-08-30 22:26:48 +0000412 def buildDsym(self):
413 """Platform specific way to build binaries with dsym info."""
Johnny Chen9de4ede2010-08-31 17:42:54 +0000414 module = __import__(sys.platform)
415 if not module.buildDsym():
Johnny Cheneef7a862010-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 Chen9de4ede2010-08-31 17:42:54 +0000420 module = __import__(sys.platform)
421 if not module.buildDwarf():
Johnny Cheneef7a862010-08-30 22:26:48 +0000422 raise Exception("Don't know how to build binary with dwarf")
423
Johnny Chen9c10c182010-08-27 00:15:48 +0000424 def DebugSBValue(self, frame, val):
Johnny Chen9de4ede2010-08-31 17:42:54 +0000425 """Debug print a SBValue object, if traceAlways is True."""
426 if not traceAlways:
Johnny Chen9c10c182010-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