lldbtest.py revision ac91027caa22212ac35de969fa53348b70e9bb28
1"""
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
16$ export PYTHONPATH=/Volumes/data/lldb/svn/trunk/build/Debug/LLDB.framework/Resources/Python:$LLDB_TEST:$LLDB_TEST/plugins
17$ echo $LLDB_TEST
18/Volumes/data/lldb/svn/trunk/test
19$ echo $PYTHONPATH
20/Volumes/data/lldb/svn/trunk/build/Debug/LLDB.framework/Resources/Python:/Volumes/data/lldb/svn/trunk/test:/Volumes/data/lldb/svn/trunk/test/plugins
21$ python function_types/TestFunctionTypes.py
22.
23----------------------------------------------------------------------
24Ran 1 test in 0.363s
25
26OK
27$ LLDB_COMMAND_TRACE=YES python array_types/TestArrayTypes.py
28
29...
30
31runCmd: breakpoint set -f main.c -l 42
32output: Breakpoint created: 1: file ='main.c', line = 42, locations = 1
33
34runCmd: run
35output: Launching '/Volumes/data/lldb/svn/trunk/test/array_types/a.out'  (x86_64)
36
37...
38
39runCmd: frame variable strings
40output: (char *[4]) strings = {
41  (char *) strings[0] = 0x0000000100000f0c "Hello",
42  (char *) strings[1] = 0x0000000100000f12 "Hola",
43  (char *) strings[2] = 0x0000000100000f17 "Bonjour",
44  (char *) strings[3] = 0x0000000100000f1f "Guten Tag"
45}
46
47runCmd: frame variable char_16
48output: (char [16]) char_16 = {
49  (char) char_16[0] = 'H',
50  (char) char_16[1] = 'e',
51  (char) char_16[2] = 'l',
52  (char) char_16[3] = 'l',
53  (char) char_16[4] = 'o',
54  (char) char_16[5] = ' ',
55  (char) char_16[6] = 'W',
56  (char) char_16[7] = 'o',
57  (char) char_16[8] = 'r',
58  (char) char_16[9] = 'l',
59  (char) char_16[10] = 'd',
60  (char) char_16[11] = '\n',
61  (char) char_16[12] = '\0',
62  (char) char_16[13] = '\0',
63  (char) char_16[14] = '\0',
64  (char) char_16[15] = '\0'
65}
66
67runCmd: frame variable ushort_matrix
68output: (unsigned short [2][3]) ushort_matrix = {
69  (unsigned short [3]) ushort_matrix[0] = {
70    (unsigned short) ushort_matrix[0][0] = 0x0001,
71    (unsigned short) ushort_matrix[0][1] = 0x0002,
72    (unsigned short) ushort_matrix[0][2] = 0x0003
73  },
74  (unsigned short [3]) ushort_matrix[1] = {
75    (unsigned short) ushort_matrix[1][0] = 0x000b,
76    (unsigned short) ushort_matrix[1][1] = 0x0016,
77    (unsigned short) ushort_matrix[1][2] = 0x0021
78  }
79}
80
81runCmd: frame variable long_6
82output: (long [6]) long_6 = {
83  (long) long_6[0] = 1,
84  (long) long_6[1] = 2,
85  (long) long_6[2] = 3,
86  (long) long_6[3] = 4,
87  (long) long_6[4] = 5,
88  (long) long_6[5] = 6
89}
90
91.
92----------------------------------------------------------------------
93Ran 1 test in 0.349s
94
95OK
96$
97"""
98
99import os, sys, traceback
100import re
101from subprocess import *
102import StringIO
103import time
104import types
105import unittest2
106import lldb
107
108# See also dotest.parseOptionsAndInitTestdirs(), where the environment variables
109# LLDB_COMMAND_TRACE and LLDB_DO_CLEANUP are set from '-t' and '-r dir' options.
110
111# By default, traceAlways is False.
112if "LLDB_COMMAND_TRACE" in os.environ and os.environ["LLDB_COMMAND_TRACE"]=="YES":
113    traceAlways = True
114else:
115    traceAlways = False
116
117# By default, doCleanup is True.
118if "LLDB_DO_CLEANUP" in os.environ and os.environ["LLDB_DO_CLEANUP"]=="NO":
119    doCleanup = False
120else:
121    doCleanup = True
122
123
124#
125# Some commonly used assert messages.
126#
127
128COMMAND_FAILED_AS_EXPECTED = "Command has failed as expected"
129
130CURRENT_EXECUTABLE_SET = "Current executable set successfully"
131
132PROCESS_IS_VALID = "Process is valid"
133
134PROCESS_KILLED = "Process is killed successfully"
135
136PROCESS_EXITED = "Process exited successfully"
137
138PROCESS_STOPPED = "Process status should be stopped"
139
140RUN_SUCCEEDED = "Process is launched successfully"
141
142RUN_COMPLETED = "Process exited successfully"
143
144BACKTRACE_DISPLAYED_CORRECTLY = "Backtrace displayed correctly"
145
146BREAKPOINT_CREATED = "Breakpoint created successfully"
147
148BREAKPOINT_STATE_CORRECT = "Breakpoint state is correct"
149
150BREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully"
151
152BREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit cout = 1"
153
154BREAKPOINT_HIT_TWICE = "Breakpoint resolved with hit cout = 2"
155
156BREAKPOINT_HIT_THRICE = "Breakpoint resolved with hit cout = 3"
157
158SOURCE_DISPLAYED_CORRECTLY = "Source code displayed correctly"
159
160STEP_OUT_SUCCEEDED = "Thread step-out succeeded"
161
162STOPPED_DUE_TO_EXC_BAD_ACCESS = "Process should be stopped due to bad access exception"
163
164STOPPED_DUE_TO_BREAKPOINT = "Process should be stopped due to breakpoint"
165
166STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS = "%s, %s" % (
167    STOPPED_DUE_TO_BREAKPOINT, "instead, the actual stop reason is: '%s'")
168
169STOPPED_DUE_TO_BREAKPOINT_CONDITION = "Stopped due to breakpoint condition"
170
171STOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT = "Stopped due to breakpoint and ignore count"
172
173STOPPED_DUE_TO_SIGNAL = "Process state is stopped due to signal"
174
175STOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in"
176
177DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly"
178
179VALID_BREAKPOINT = "Got a valid breakpoint"
180
181VALID_BREAKPOINT_LOCATION = "Got a valid breakpoint location"
182
183VALID_COMMAND_INTERPRETER = "Got a valid command interpreter"
184
185VALID_FILESPEC = "Got a valid filespec"
186
187VALID_MODULE = "Got a valid module"
188
189VALID_PROCESS = "Got a valid process"
190
191VALID_SYMBOL = "Got a valid symbol"
192
193VALID_TARGET = "Got a valid target"
194
195VARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly"
196
197
198#
199# And a generic "Command '%s' returns successfully" message generator.
200#
201def CMD_MSG(str):
202    return "Command '%s' returns successfully" % str
203
204#
205# And a generic "'%s' returns expected result" message generator if exe.
206# Otherwise, it's "'%s' matches expected result"
207#
208def EXP_MSG(str, exe):
209    return "'%s' %s expected result" % (str, 'returns' if exe else 'matches')
210
211#
212# And a generic "Value of setting '%s' is correct" message generator.
213#
214def SETTING_MSG(setting):
215    return "Value of setting '%s' is correct" % setting
216
217#
218# Returns an env variable array from the os.environ map object.
219#
220def EnvArray():
221    return map(lambda k,v: k+"="+v, os.environ.keys(), os.environ.values())
222
223def line_number(filename, string_to_match):
224    """Helper function to return the line number of the first matched string."""
225    with open(filename, 'r') as f:
226        for i, line in enumerate(f):
227            if line.find(string_to_match) != -1:
228                # Found our match.
229                return i+1
230    raise Exception("Unable to find '%s' within file %s" % (string_to_match, filename))
231
232def pointer_size():
233    """Return the pointer size of the host system."""
234    import ctypes
235    a_pointer = ctypes.c_void_p(0xffff)
236    return 8 * ctypes.sizeof(a_pointer)
237
238from functools import wraps
239def python_api_test(func):
240    """Decorate the item as a Python API only test."""
241    if isinstance(func, type) and issubclass(func, unittest2.TestCase):
242        raise Exception("@python_api_test can only be used to decorate a test method")
243    @wraps(func)
244    def wrapper(self, *args, **kwargs):
245        if lldb.dont_do_python_api_test:
246            self.skipTest("Skip Python API tests")
247        return func(self, *args, **kwargs)
248
249    # Mark this function as such to separate them from lldb command line tests.
250    wrapper.__python_api_test__ = True
251    return wrapper
252
253class recording(StringIO.StringIO):
254    """
255    A nice little context manager for recording the debugger interactions into
256    our session object.  If trace flag is ON, it also emits the interactions
257    into the stderr.
258    """
259    def __init__(self, test, trace):
260        """Create a StringIO instance; record the session obj and trace flag."""
261        StringIO.StringIO.__init__(self)
262        self.session = test.session if test else None
263        self.trace = trace
264
265    def __enter__(self):
266        """
267        Context management protocol on entry to the body of the with statement.
268        Just return the StringIO object.
269        """
270        return self
271
272    def __exit__(self, type, value, tb):
273        """
274        Context management protocol on exit from the body of the with statement.
275        If trace is ON, it emits the recordings into stderr.  Always add the
276        recordings to our session object.  And close the StringIO object, too.
277        """
278        if self.trace:
279            print >> sys.stderr, self.getvalue()
280        if self.session:
281            print >> self.session, self.getvalue()
282        self.close()
283
284# From 2.7's subprocess.check_output() convenience function.
285# Return a tuple (stdoutdata, stderrdata).
286def system(*popenargs, **kwargs):
287    r"""Run command with arguments and return its output as a byte string.
288
289    If the exit code was non-zero it raises a CalledProcessError.  The
290    CalledProcessError object will have the return code in the returncode
291    attribute and output in the output attribute.
292
293    The arguments are the same as for the Popen constructor.  Example:
294
295    >>> check_output(["ls", "-l", "/dev/null"])
296    'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'
297
298    The stdout argument is not allowed as it is used internally.
299    To capture standard error in the result, use stderr=STDOUT.
300
301    >>> check_output(["/bin/sh", "-c",
302    ...               "ls -l non_existent_file ; exit 0"],
303    ...              stderr=STDOUT)
304    'ls: non_existent_file: No such file or directory\n'
305    """
306
307    # Assign the sender object to variable 'test' and remove it from kwargs.
308    test = kwargs.pop('sender', None)
309
310    if 'stdout' in kwargs:
311        raise ValueError('stdout argument not allowed, it will be overridden.')
312    process = Popen(stdout=PIPE, stderr=PIPE, *popenargs, **kwargs)
313    output, error = process.communicate()
314    retcode = process.poll()
315
316    with recording(test, traceAlways) as sbuf:
317        if isinstance(popenargs, types.StringTypes):
318            args = [popenargs]
319        else:
320            args = list(popenargs)
321        print >> sbuf
322        print >> sbuf, "os command:", args
323        print >> sbuf, "stdout:", output
324        print >> sbuf, "stderr:", error
325        print >> sbuf, "retcode:", retcode
326        print >> sbuf
327
328    if retcode:
329        cmd = kwargs.get("args")
330        if cmd is None:
331            cmd = popenargs[0]
332        raise CalledProcessError(retcode, cmd)
333    return (output, error)
334
335def getsource_if_available(obj):
336    """
337    Return the text of the source code for an object if available.  Otherwise,
338    a print representation is returned.
339    """
340    import inspect
341    try:
342        return inspect.getsource(obj)
343    except:
344        return repr(obj)
345
346class TestBase(unittest2.TestCase):
347    """
348    This abstract base class is meant to be subclassed.  It provides default
349    implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(),
350    among other things.
351
352    Important things for test class writers:
353
354        - Overwrite the mydir class attribute, otherwise your test class won't
355          run.  It specifies the relative directory to the top level 'test' so
356          the test harness can change to the correct working directory before
357          running your test.
358
359        - The setUp method sets up things to facilitate subsequent interactions
360          with the debugger as part of the test.  These include:
361              - create/get a debugger set with synchronous mode (self.dbg)
362              - get the command interpreter from with the debugger (self.ci)
363              - create a result object for use with the command interpreter
364                (self.result)
365              - plus other stuffs
366
367        - The tearDown method tries to perform some necessary cleanup on behalf
368          of the test to return the debugger to a good state for the next test.
369          These include:
370              - execute any tearDown hooks registered by the test method with
371                TestBase.addTearDownHook(); examples can be found in
372                settings/TestSettings.py
373              - kill the inferior process launched during the test method
374                    - if by 'run' or 'process launch' command, 'process kill'
375                      command is used
376                    - if the test method uses LLDB Python API to launch process,
377                      it should assign the process object to self.process; that
378                      way, tearDown will use self.process.Kill() on the object
379              - perform build cleanup before running the next test method in the
380                same test class; examples of registering for this service can be
381                found in types/TestIntegerTypes.py with the call:
382                    - self.setTearDownCleanup(dictionary=d)
383
384        - Similarly setUpClass and tearDownClass perform classwise setup and
385          teardown fixtures.  The tearDownClass method invokes a default build
386          cleanup for the entire test class;  also, subclasses can implement the
387          classmethod classCleanup(cls) to perform special class cleanup action.
388
389        - The instance methods runCmd and expect are used heavily by existing
390          test cases to send a command to the command interpreter and to perform
391          string/pattern matching on the output of such command execution.  The
392          expect method also provides a mode to peform string/pattern matching
393          without running a command.
394
395        - The build methods buildDefault, buildDsym, and buildDwarf are used to
396          build the binaries used during a particular test scenario.  A plugin
397          should be provided for the sys.platform running the test suite.  The
398          Mac OS X implementation is located in plugins/darwin.py.
399
400    """
401
402    @classmethod
403    def skipLongRunningTest(cls):
404        """
405        By default, we skip long running test case.
406        This can be overridden by passing '-l' to the test driver (dotest.py).
407        """
408        if "LLDB_SKIP_LONG_RUNNING_TEST" in os.environ and "NO" == os.environ["LLDB_SKIP_LONG_RUNNING_TEST"]:
409            return False
410        else:
411            return True
412
413    # The concrete subclass should override this attribute.
414    mydir = None
415
416    # State pertaining to the inferior process, if any.
417    # This reflects inferior process started through the command interface with
418    # either the lldb "run" or "process launch" command.
419    # See also self.runCmd().
420    runStarted = False
421
422    # Maximum allowed attempts when launching the inferior process.
423    # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable.
424    maxLaunchCount = 3;
425
426    # Time to wait before the next launching attempt in second(s).
427    # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable.
428    timeWaitNextLaunch = 1.0;
429
430    # Keep track of the old current working directory.
431    oldcwd = None
432
433    @classmethod
434    def setUpClass(cls):
435        """
436        Python unittest framework class setup fixture.
437        Do current directory manipulation.
438        """
439
440        # Fail fast if 'mydir' attribute is not overridden.
441        if not cls.mydir or len(cls.mydir) == 0:
442            raise Exception("Subclasses must override the 'mydir' attribute.")
443        # Save old working directory.
444        cls.oldcwd = os.getcwd()
445
446        # Change current working directory if ${LLDB_TEST} is defined.
447        # See also dotest.py which sets up ${LLDB_TEST}.
448        if ("LLDB_TEST" in os.environ):
449            if traceAlways:
450                print >> sys.stderr, "Change dir to:", os.path.join(os.environ["LLDB_TEST"], cls.mydir)
451            os.chdir(os.path.join(os.environ["LLDB_TEST"], cls.mydir))
452
453    @classmethod
454    def tearDownClass(cls):
455        """
456        Python unittest framework class teardown fixture.
457        Do class-wide cleanup.
458        """
459
460        if doCleanup:
461            # First, let's do the platform-specific cleanup.
462            module = __import__(sys.platform)
463            if not module.cleanup():
464                raise Exception("Don't know how to do cleanup")
465
466            # Subclass might have specific cleanup function defined.
467            if getattr(cls, "classCleanup", None):
468                if traceAlways:
469                    print >> sys.stderr, "Call class-specific cleanup function for class:", cls
470                try:
471                    cls.classCleanup()
472                except:
473                    exc_type, exc_value, exc_tb = sys.exc_info()
474                    traceback.print_exception(exc_type, exc_value, exc_tb)
475
476        # Restore old working directory.
477        if traceAlways:
478            print >> sys.stderr, "Restore dir to:", cls.oldcwd
479        os.chdir(cls.oldcwd)
480
481    def setUp(self):
482        #import traceback
483        #traceback.print_stack()
484
485        if "LLDB_EXEC" in os.environ:
486            self.lldbExec = os.environ["LLDB_EXEC"]
487
488        if lldb.blacklist:
489            className = self.__class__.__name__
490            classAndMethodName = "%s.%s" % (className, self._testMethodName)
491            if className in lldb.blacklist:
492                self.skipTest(lldb.blacklist.get(className))
493            elif classAndMethodName in lldb.blacklist:
494                self.skipTest(lldb.blacklist.get(classAndMethodName))
495
496        # Python API only test is decorated with @python_api_test,
497        # which also sets the "__python_api_test__" attribute of the
498        # function object to True.
499        if lldb.just_do_python_api_test:
500            testMethod = getattr(self, self._testMethodName)
501            if getattr(testMethod, "__python_api_test__", False):
502                pass
503            else:
504                self.skipTest("Skip lldb command line test")
505
506        if ("LLDB_WAIT_BETWEEN_TEST_CASES" in os.environ and
507            os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] == 'YES'):
508            waitTime = 1.0
509            if "LLDB_TIME_WAIT_BETWEEN_TEST_CASES" in os.environ:
510                waitTime = float(os.environ["LLDB_TIME_WAIT_BETWEEN_TEST_CASES"])
511            time.sleep(waitTime)
512
513        if "LLDB_MAX_LAUNCH_COUNT" in os.environ:
514            self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"])
515
516        if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ:
517            self.timeWaitNextLaunch = float(os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"])
518
519        # Create the debugger instance if necessary.
520        try:
521            self.dbg = lldb.DBG
522        except AttributeError:
523            self.dbg = lldb.SBDebugger.Create()
524
525        if not self.dbg.IsValid():
526            raise Exception('Invalid debugger instance')
527
528        # We want our debugger to be synchronous.
529        self.dbg.SetAsync(False)
530
531        # This is for the case of directly spawning 'lldb' and interacting with
532        # it using pexpect.
533        self.child = None
534        # If the child is interacting with the embedded script interpreter,
535        # there are two exits required during tear down, first to quit the
536        # embedded script interpreter and second to quit the lldb command
537        # interpreter.
538        self.child_in_script_interpreter = False
539
540        # There is no process associated with the debugger as yet.
541        # See also self.tearDown() where it checks whether self.process has a
542        # valid reference and calls self.process.Kill() to kill the process.
543        self.process = None
544
545        # Retrieve the associated command interpreter instance.
546        self.ci = self.dbg.GetCommandInterpreter()
547        if not self.ci:
548            raise Exception('Could not get the command interpreter')
549
550        # And the result object.
551        self.res = lldb.SBCommandReturnObject()
552
553        # These are for customized teardown cleanup.
554        self.dict = None
555        self.doTearDownCleanup = False
556        # And in rare cases where there are multiple teardown cleanups.
557        self.dicts = []
558        self.doTearDownCleanups = False
559
560        # Create a string buffer to record the session info, to be dumped into a
561        # test case specific file if test failure is encountered.
562        self.session = StringIO.StringIO()
563
564        # Optimistically set __errored__, __failed__, __expected__ to False
565        # initially.  If the test errored/failed, the session info
566        # (self.session) is then dumped into a session specific file for
567        # diagnosis.
568        self.__errored__    = False
569        self.__failed__     = False
570        self.__expected__   = False
571        # We are also interested in unexpected success.
572        self.__unexpected__ = False
573
574        # See addTearDownHook(self, hook) which allows the client to add a hook
575        # function to be run during tearDown() time.
576        self.hooks = []
577
578        # See HideStdout(self).
579        self.sys_stdout_hidden = False
580
581    def markError(self):
582        """Callback invoked when an error (unexpected exception) errored."""
583        self.__errored__ = True
584        with recording(self, False) as sbuf:
585            # False because there's no need to write "ERROR" to the stderr twice.
586            # Once by the Python unittest framework, and a second time by us.
587            print >> sbuf, "ERROR"
588
589    def markFailure(self):
590        """Callback invoked when a failure (test assertion failure) occurred."""
591        self.__failed__ = True
592        with recording(self, False) as sbuf:
593            # False because there's no need to write "FAIL" to the stderr twice.
594            # Once by the Python unittest framework, and a second time by us.
595            print >> sbuf, "FAIL"
596
597    def markExpectedFailure(self):
598        """Callback invoked when an expected failure/error occurred."""
599        self.__expected__ = True
600        with recording(self, False) as sbuf:
601            # False because there's no need to write "expected failure" to the
602            # stderr twice.
603            # Once by the Python unittest framework, and a second time by us.
604            print >> sbuf, "expected failure"
605
606    def markUnexpectedSuccess(self):
607        """Callback invoked when an unexpected success occurred."""
608        self.__unexpected__ = True
609        with recording(self, False) as sbuf:
610            # False because there's no need to write "unexpected success" to the
611            # stderr twice.
612            # Once by the Python unittest framework, and a second time by us.
613            print >> sbuf, "unexpected success"
614
615    def dumpSessionInfo(self):
616        """
617        Dump the debugger interactions leading to a test error/failure.  This
618        allows for more convenient postmortem analysis.
619
620        See also LLDBTestResult (dotest.py) which is a singlton class derived
621        from TextTestResult and overwrites addError, addFailure, and
622        addExpectedFailure methods to allow us to to mark the test instance as
623        such.
624        """
625
626        # We are here because self.tearDown() detected that this test instance
627        # either errored or failed.  The lldb.test_result singleton contains
628        # two lists (erros and failures) which get populated by the unittest
629        # framework.  Look over there for stack trace information.
630        #
631        # The lists contain 2-tuples of TestCase instances and strings holding
632        # formatted tracebacks.
633        #
634        # See http://docs.python.org/library/unittest.html#unittest.TestResult.
635        if self.__errored__:
636            pairs = lldb.test_result.errors
637            prefix = 'Error'
638        elif self.__failed__:
639            pairs = lldb.test_result.failures
640            prefix = 'Failure'
641        elif self.__expected__:
642            pairs = lldb.test_result.expectedFailures
643            prefix = 'ExpectedFailure'
644        elif self.__unexpected__:
645            prefix = "UnexpectedSuccess"
646        else:
647            # Simply return, there's no session info to dump!
648            return
649
650        if not self.__unexpected__:
651            for test, traceback in pairs:
652                if test is self:
653                    print >> self.session, traceback
654
655        dname = os.path.join(os.environ["LLDB_TEST"],
656                             os.environ["LLDB_SESSION_DIRNAME"])
657        if not os.path.isdir(dname):
658            os.mkdir(dname)
659        fname = os.path.join(dname, "%s-%s.log" % (prefix, self.id()))
660        with open(fname, "w") as f:
661            import datetime
662            print >> f, "Session info generated @", datetime.datetime.now().ctime()
663            print >> f, self.session.getvalue()
664            print >> f, "To rerun this test, issue the following command from the 'test' directory:\n"
665            print >> f, "./dotest.py %s -v -t -f %s.%s" % (self.getRunOptions(),
666                                                           self.__class__.__name__,
667                                                           self._testMethodName)
668
669    def setTearDownCleanup(self, dictionary=None):
670        """Register a cleanup action at tearDown() time with a dictinary"""
671        self.dict = dictionary
672        self.doTearDownCleanup = True
673
674    def addTearDownCleanup(self, dictionary):
675        """Add a cleanup action at tearDown() time with a dictinary"""
676        self.dicts.append(dictionary)
677        self.doTearDownCleanups = True
678
679    def addTearDownHook(self, hook):
680        """
681        Add a function to be run during tearDown() time.
682
683        Hooks are executed in a first come first serve manner.
684        """
685        if callable(hook):
686            with recording(self, traceAlways) as sbuf:
687                print >> sbuf, "Adding tearDown hook:", getsource_if_available(hook)
688            self.hooks.append(hook)
689
690    def tearDown(self):
691        #import traceback
692        #traceback.print_stack()
693
694        # Check and run any hook functions.
695        for hook in reversed(self.hooks):
696            with recording(self, traceAlways) as sbuf:
697                print >> sbuf, "Executing tearDown hook:", getsource_if_available(hook)
698            hook()
699
700        # This is for the case of directly spawning 'lldb' and interacting with it
701        # using pexpect.
702        import pexpect
703        if self.child and self.child.isalive():
704            with recording(self, traceAlways) as sbuf:
705                print >> sbuf, "tearing down the child process...."
706            if self.child_in_script_interpreter:
707                self.child.sendline('quit()')
708                self.child.expect_exact('(lldb) ')
709            self.child.sendline('quit')
710            try:
711                self.child.expect(pexpect.EOF)
712            except:
713                pass
714
715        # Terminate the current process being debugged, if any.
716        if self.runStarted:
717            self.runCmd("process kill", PROCESS_KILLED, check=False)
718        elif self.process and self.process.IsValid():
719            rc = self.invoke(self.process, "Kill")
720            self.assertTrue(rc.Success(), PROCESS_KILLED)
721            del self.process
722
723        del self.dbg
724        del self.hooks
725
726        # Perform registered teardown cleanup.
727        if doCleanup and self.doTearDownCleanup:
728            module = __import__(sys.platform)
729            if not module.cleanup(self, dictionary=self.dict):
730                raise Exception("Don't know how to do cleanup with dictionary: " + self.dict)
731
732        # In rare cases where there are multiple teardown cleanups added.
733        if doCleanup and self.doTearDownCleanups:
734            module = __import__(sys.platform)
735            if self.dicts:
736                for dict in reversed(self.dicts):
737                    if not module.cleanup(self, dictionary=dict):
738                        raise Exception("Don't know how to do cleanup with dictionary: " + dict)
739
740        # Decide whether to dump the session info.
741        self.dumpSessionInfo()
742
743    def runCmd(self, cmd, msg=None, check=True, trace=False, setCookie=True):
744        """
745        Ask the command interpreter to handle the command and then check its
746        return status.
747        """
748        # Fail fast if 'cmd' is not meaningful.
749        if not cmd or len(cmd) == 0:
750            raise Exception("Bad 'cmd' parameter encountered")
751
752        trace = (True if traceAlways else trace)
753
754        running = (cmd.startswith("run") or cmd.startswith("process launch"))
755
756        for i in range(self.maxLaunchCount if running else 1):
757            self.ci.HandleCommand(cmd, self.res)
758
759            with recording(self, trace) as sbuf:
760                print >> sbuf, "runCmd:", cmd
761                if not check:
762                    print >> sbuf, "check of return status not required"
763                if self.res.Succeeded():
764                    print >> sbuf, "output:", self.res.GetOutput()
765                else:
766                    print >> sbuf, "runCmd failed!"
767                    print >> sbuf, self.res.GetError()
768
769            if self.res.Succeeded():
770                break
771            elif running:
772                # For process launch, wait some time before possible next try.
773                time.sleep(self.timeWaitNextLaunch)
774                with recording(self, True) as sbuf:
775                    print >> sbuf, "Command '" + cmd + "' failed!"
776
777        # Modify runStarted only if "run" or "process launch" was encountered.
778        if running:
779            self.runStarted = running and setCookie
780
781        if check:
782            self.assertTrue(self.res.Succeeded(),
783                            msg if msg else CMD_MSG(cmd))
784
785    def expect(self, str, msg=None, patterns=None, startstr=None, substrs=None, trace=False, error=False, matching=True, exe=True):
786        """
787        Similar to runCmd; with additional expect style output matching ability.
788
789        Ask the command interpreter to handle the command and then check its
790        return status.  The 'msg' parameter specifies an informational assert
791        message.  We expect the output from running the command to start with
792        'startstr', matches the substrings contained in 'substrs', and regexp
793        matches the patterns contained in 'patterns'.
794
795        If the keyword argument error is set to True, it signifies that the API
796        client is expecting the command to fail.  In this case, the error stream
797        from running the command is retrieved and compared against the golden
798        input, instead.
799
800        If the keyword argument matching is set to False, it signifies that the API
801        client is expecting the output of the command not to match the golden
802        input.
803
804        Finally, the required argument 'str' represents the lldb command to be
805        sent to the command interpreter.  In case the keyword argument 'exe' is
806        set to False, the 'str' is treated as a string to be matched/not-matched
807        against the golden input.
808        """
809        trace = (True if traceAlways else trace)
810
811        if exe:
812            # First run the command.  If we are expecting error, set check=False.
813            # Pass the assert message along since it provides more semantic info.
814            self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error)
815
816            # Then compare the output against expected strings.
817            output = self.res.GetError() if error else self.res.GetOutput()
818
819            # If error is True, the API client expects the command to fail!
820            if error:
821                self.assertFalse(self.res.Succeeded(),
822                                 "Command '" + str + "' is expected to fail!")
823        else:
824            # No execution required, just compare str against the golden input.
825            output = str
826            with recording(self, trace) as sbuf:
827                print >> sbuf, "looking at:", output
828
829        # The heading says either "Expecting" or "Not expecting".
830        heading = "Expecting" if matching else "Not expecting"
831
832        # Start from the startstr, if specified.
833        # If there's no startstr, set the initial state appropriately.
834        matched = output.startswith(startstr) if startstr else (True if matching else False)
835
836        if startstr:
837            with recording(self, trace) as sbuf:
838                print >> sbuf, "%s start string: %s" % (heading, startstr)
839                print >> sbuf, "Matched" if matched else "Not matched"
840
841        # Look for sub strings, if specified.
842        keepgoing = matched if matching else not matched
843        if substrs and keepgoing:
844            for str in substrs:
845                matched = output.find(str) != -1
846                with recording(self, trace) as sbuf:
847                    print >> sbuf, "%s sub string: %s" % (heading, str)
848                    print >> sbuf, "Matched" if matched else "Not matched"
849                keepgoing = matched if matching else not matched
850                if not keepgoing:
851                    break
852
853        # Search for regular expression patterns, if specified.
854        keepgoing = matched if matching else not matched
855        if patterns and keepgoing:
856            for pattern in patterns:
857                # Match Objects always have a boolean value of True.
858                matched = bool(re.search(pattern, output))
859                with recording(self, trace) as sbuf:
860                    print >> sbuf, "%s pattern: %s" % (heading, pattern)
861                    print >> sbuf, "Matched" if matched else "Not matched"
862                keepgoing = matched if matching else not matched
863                if not keepgoing:
864                    break
865
866        self.assertTrue(matched if matching else not matched,
867                        msg if msg else EXP_MSG(str, exe))
868
869    def invoke(self, obj, name, trace=False):
870        """Use reflection to call a method dynamically with no argument."""
871        trace = (True if traceAlways else trace)
872
873        method = getattr(obj, name)
874        import inspect
875        self.assertTrue(inspect.ismethod(method),
876                        name + "is a method name of object: " + str(obj))
877        result = method()
878        with recording(self, trace) as sbuf:
879            print >> sbuf, str(method) + ":",  result
880        return result
881
882    def breakAfterLaunch(self, process, func, trace=False):
883        """
884        Perform some dances after Launch() to break at func name.
885
886        Return True if we can successfully break at the func name in due time.
887        """
888        trace = (True if traceAlways else trace)
889
890        count = 0
891        while True:
892            # The stop reason of the thread should be breakpoint.
893            thread = process.GetThreadAtIndex(0)
894            SR = thread.GetStopReason()
895            with recording(self, trace) as sbuf:
896                print >> sbuf, "StopReason =", stop_reason_to_str(SR)
897
898            if SR == lldb.eStopReasonBreakpoint:
899                frame = thread.GetFrameAtIndex(0)
900                name = frame.GetFunction().GetName()
901                with recording(self, trace) as sbuf:
902                    print >> sbuf, "function =", name
903                if (name == func):
904                    # We got what we want; now break out of the loop.
905                    return True
906
907            # The inferior is in a transient state; continue the process.
908            time.sleep(1.0)
909            with recording(self, trace) as sbuf:
910                print >> sbuf, "Continuing the process:", process
911            process.Continue()
912
913            count = count + 1
914            if count == 15:
915                with recording(self, trace) as sbuf:
916                    print >> sbuf, "Reached 15 iterations, giving up..."
917                # Enough iterations already, break out of the loop.
918                return False
919
920            # End of while loop.
921
922
923    def getArchitecture(self):
924        """Returns the architecture in effect the test suite is now running with."""
925        module = __import__(sys.platform)
926        return module.getArchitecture()
927
928    def getCompiler(self):
929        """Returns the compiler in effect the test suite is now running with."""
930        module = __import__(sys.platform)
931        return module.getCompiler()
932
933    def getRunOptions(self):
934        """Command line option for -A and -C to run this test again, called from
935        within dumpSessionInfo()."""
936        module = __import__(sys.platform)
937        arch = self.getArchitecture()
938        comp = self.getCompiler()
939        if not arch and not comp:
940            return ""
941        else:
942            return "%s %s" % ("-A "+arch if arch else "",
943                              "-C "+comp if comp else "")
944
945    def buildDefault(self, architecture=None, compiler=None, dictionary=None):
946        """Platform specific way to build the default binaries."""
947        module = __import__(sys.platform)
948        if not module.buildDefault(self, architecture, compiler, dictionary):
949            raise Exception("Don't know how to build default binary")
950
951    def buildDsym(self, architecture=None, compiler=None, dictionary=None):
952        """Platform specific way to build binaries with dsym info."""
953        module = __import__(sys.platform)
954        if not module.buildDsym(self, architecture, compiler, dictionary):
955            raise Exception("Don't know how to build binary with dsym")
956
957    def buildDwarf(self, architecture=None, compiler=None, dictionary=None):
958        """Platform specific way to build binaries with dwarf maps."""
959        module = __import__(sys.platform)
960        if not module.buildDwarf(self, architecture, compiler, dictionary):
961            raise Exception("Don't know how to build binary with dwarf")
962
963    def DebugSBValue(self, frame, val):
964        """Debug print a SBValue object, if traceAlways is True."""
965        from lldbutil import value_type_to_str
966
967        if not traceAlways:
968            return
969
970        err = sys.stderr
971        err.write(val.GetName() + ":\n")
972        err.write('\t' + "TypeName      -> " + val.GetTypeName()            + '\n')
973        err.write('\t' + "ByteSize      -> " + str(val.GetByteSize())       + '\n')
974        err.write('\t' + "NumChildren   -> " + str(val.GetNumChildren())    + '\n')
975        err.write('\t' + "Value         -> " + str(val.GetValue(frame))     + '\n')
976        err.write('\t' + "ValueType     -> " + value_type_to_str(val.GetValueType()) + '\n')
977        err.write('\t' + "Summary       -> " + str(val.GetSummary(frame))   + '\n')
978        err.write('\t' + "IsPointerType -> " + str(val.TypeIsPointerType()) + '\n')
979        err.write('\t' + "Location      -> " + val.GetLocation(frame)       + '\n')
980
981    def DebugPExpect(self, child):
982        """Debug the spwaned pexpect object."""
983        if not traceAlways:
984            return
985
986        print child
987
988    def TraceOn(self):
989        """Returns True if we are in trace mode (i.e., tracing lldb command execution)."""
990        return traceAlways
991
992    def HideStdout(self):
993        """Hide output to stdout from the user.
994
995        During test execution, there might be cases where we don't want to show the
996        standard output to the user.  For example,
997
998            self.runCmd(r'''sc print "\n\n\tHello!\n"''')
999
1000        tests whether command abbreviation for 'script' works or not.  There is no
1001        need to show the 'Hello' output to the user as long as the 'script' command
1002        succeeds and we are not in TraceOn() mode (see the '-t' option).
1003
1004        In this case, the test method calls self.HideStdout(self) to redirect the
1005        sys.stdout to a null device, and restores the sys.stdout upon teardown.
1006
1007        Note that you should only call this method at most once during a test case
1008        execution.  Any subsequent call has no effect at all."""
1009        if self.sys_stdout_hidden:
1010            return
1011
1012        self.sys_stdout_hidden = True
1013        old_stdout = sys.stdout
1014        sys.stdout = open(os.devnull, 'w')
1015        def restore_stdout():
1016            sys.stdout = old_stdout
1017        self.addTearDownHook(restore_stdout)
1018