lldbtest.py revision 4d82e973c42d78ac83bcd819329ca017f6dcabb5
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 of part of the test suite . Example: 13 14# Exercises the test suite in the types directory.... 15/Volumes/data/lldb/svn/ToT/test $ ./dotest.py -A x86_64 types 16... 17 18Session logs for test failures/errors/unexpected successes will go into directory '2012-05-16-13_35_42' 19Command invoked: python ./dotest.py -A x86_64 types 20compilers=['clang'] 21 22Configuration: arch=x86_64 compiler=clang 23---------------------------------------------------------------------- 24Collected 72 tests 25 26........................................................................ 27---------------------------------------------------------------------- 28Ran 72 tests in 135.468s 29 30OK 31$ 32""" 33 34import os, sys, traceback 35import os.path 36import re 37from subprocess import * 38import StringIO 39import time 40import types 41import unittest2 42import lldb 43 44# See also dotest.parseOptionsAndInitTestdirs(), where the environment variables 45# LLDB_COMMAND_TRACE and LLDB_DO_CLEANUP are set from '-t' and '-r dir' options. 46 47# By default, traceAlways is False. 48if "LLDB_COMMAND_TRACE" in os.environ and os.environ["LLDB_COMMAND_TRACE"]=="YES": 49 traceAlways = True 50else: 51 traceAlways = False 52 53# By default, doCleanup is True. 54if "LLDB_DO_CLEANUP" in os.environ and os.environ["LLDB_DO_CLEANUP"]=="NO": 55 doCleanup = False 56else: 57 doCleanup = True 58 59 60# 61# Some commonly used assert messages. 62# 63 64COMMAND_FAILED_AS_EXPECTED = "Command has failed as expected" 65 66CURRENT_EXECUTABLE_SET = "Current executable set successfully" 67 68PROCESS_IS_VALID = "Process is valid" 69 70PROCESS_KILLED = "Process is killed successfully" 71 72PROCESS_EXITED = "Process exited successfully" 73 74PROCESS_STOPPED = "Process status should be stopped" 75 76RUN_SUCCEEDED = "Process is launched successfully" 77 78RUN_COMPLETED = "Process exited successfully" 79 80BACKTRACE_DISPLAYED_CORRECTLY = "Backtrace displayed correctly" 81 82BREAKPOINT_CREATED = "Breakpoint created successfully" 83 84BREAKPOINT_STATE_CORRECT = "Breakpoint state is correct" 85 86BREAKPOINT_PENDING_CREATED = "Pending breakpoint created successfully" 87 88BREAKPOINT_HIT_ONCE = "Breakpoint resolved with hit cout = 1" 89 90BREAKPOINT_HIT_TWICE = "Breakpoint resolved with hit cout = 2" 91 92BREAKPOINT_HIT_THRICE = "Breakpoint resolved with hit cout = 3" 93 94MISSING_EXPECTED_REGISTERS = "At least one expected register is unavailable." 95 96OBJECT_PRINTED_CORRECTLY = "Object printed correctly" 97 98SOURCE_DISPLAYED_CORRECTLY = "Source code displayed correctly" 99 100STEP_OUT_SUCCEEDED = "Thread step-out succeeded" 101 102STOPPED_DUE_TO_EXC_BAD_ACCESS = "Process should be stopped due to bad access exception" 103 104STOPPED_DUE_TO_BREAKPOINT = "Process should be stopped due to breakpoint" 105 106STOPPED_DUE_TO_BREAKPOINT_WITH_STOP_REASON_AS = "%s, %s" % ( 107 STOPPED_DUE_TO_BREAKPOINT, "instead, the actual stop reason is: '%s'") 108 109STOPPED_DUE_TO_BREAKPOINT_CONDITION = "Stopped due to breakpoint condition" 110 111STOPPED_DUE_TO_BREAKPOINT_IGNORE_COUNT = "Stopped due to breakpoint and ignore count" 112 113STOPPED_DUE_TO_SIGNAL = "Process state is stopped due to signal" 114 115STOPPED_DUE_TO_STEP_IN = "Process state is stopped due to step in" 116 117STOPPED_DUE_TO_WATCHPOINT = "Process should be stopped due to watchpoint" 118 119DATA_TYPES_DISPLAYED_CORRECTLY = "Data type(s) displayed correctly" 120 121VALID_BREAKPOINT = "Got a valid breakpoint" 122 123VALID_BREAKPOINT_LOCATION = "Got a valid breakpoint location" 124 125VALID_COMMAND_INTERPRETER = "Got a valid command interpreter" 126 127VALID_FILESPEC = "Got a valid filespec" 128 129VALID_MODULE = "Got a valid module" 130 131VALID_PROCESS = "Got a valid process" 132 133VALID_SYMBOL = "Got a valid symbol" 134 135VALID_TARGET = "Got a valid target" 136 137VALID_TYPE = "Got a valid type" 138 139VALID_VARIABLE = "Got a valid variable" 140 141VARIABLES_DISPLAYED_CORRECTLY = "Variable(s) displayed correctly" 142 143WATCHPOINT_CREATED = "Watchpoint created successfully" 144 145def CMD_MSG(str): 146 '''A generic "Command '%s' returns successfully" message generator.''' 147 return "Command '%s' returns successfully" % str 148 149def COMPLETION_MSG(str_before, str_after): 150 '''A generic message generator for the completion mechanism.''' 151 return "'%s' successfully completes to '%s'" % (str_before, str_after) 152 153def EXP_MSG(str, exe): 154 '''A generic "'%s' returns expected result" message generator if exe. 155 Otherwise, it generates "'%s' matches expected result" message.''' 156 return "'%s' %s expected result" % (str, 'returns' if exe else 'matches') 157 158def SETTING_MSG(setting): 159 '''A generic "Value of setting '%s' is correct" message generator.''' 160 return "Value of setting '%s' is correct" % setting 161 162def EnvArray(): 163 """Returns an env variable array from the os.environ map object.""" 164 return map(lambda k,v: k+"="+v, os.environ.keys(), os.environ.values()) 165 166def line_number(filename, string_to_match): 167 """Helper function to return the line number of the first matched string.""" 168 with open(filename, 'r') as f: 169 for i, line in enumerate(f): 170 if line.find(string_to_match) != -1: 171 # Found our match. 172 return i+1 173 raise Exception("Unable to find '%s' within file %s" % (string_to_match, filename)) 174 175def pointer_size(): 176 """Return the pointer size of the host system.""" 177 import ctypes 178 a_pointer = ctypes.c_void_p(0xffff) 179 return 8 * ctypes.sizeof(a_pointer) 180 181def is_exe(fpath): 182 """Returns true if fpath is an executable.""" 183 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 184 185def which(program): 186 """Returns the full path to a program; None otherwise.""" 187 fpath, fname = os.path.split(program) 188 if fpath: 189 if is_exe(program): 190 return program 191 else: 192 for path in os.environ["PATH"].split(os.pathsep): 193 exe_file = os.path.join(path, program) 194 if is_exe(exe_file): 195 return exe_file 196 return None 197 198class recording(StringIO.StringIO): 199 """ 200 A nice little context manager for recording the debugger interactions into 201 our session object. If trace flag is ON, it also emits the interactions 202 into the stderr. 203 """ 204 def __init__(self, test, trace): 205 """Create a StringIO instance; record the session obj and trace flag.""" 206 StringIO.StringIO.__init__(self) 207 # The test might not have undergone the 'setUp(self)' phase yet, so that 208 # the attribute 'session' might not even exist yet. 209 self.session = getattr(test, "session", None) if test else None 210 self.trace = trace 211 212 def __enter__(self): 213 """ 214 Context management protocol on entry to the body of the with statement. 215 Just return the StringIO object. 216 """ 217 return self 218 219 def __exit__(self, type, value, tb): 220 """ 221 Context management protocol on exit from the body of the with statement. 222 If trace is ON, it emits the recordings into stderr. Always add the 223 recordings to our session object. And close the StringIO object, too. 224 """ 225 if self.trace: 226 print >> sys.stderr, self.getvalue() 227 if self.session: 228 print >> self.session, self.getvalue() 229 self.close() 230 231# From 2.7's subprocess.check_output() convenience function. 232# Return a tuple (stdoutdata, stderrdata). 233def system(*popenargs, **kwargs): 234 r"""Run an os command with arguments and return its output as a byte string. 235 236 If the exit code was non-zero it raises a CalledProcessError. The 237 CalledProcessError object will have the return code in the returncode 238 attribute and output in the output attribute. 239 240 The arguments are the same as for the Popen constructor. Example: 241 242 >>> check_output(["ls", "-l", "/dev/null"]) 243 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n' 244 245 The stdout argument is not allowed as it is used internally. 246 To capture standard error in the result, use stderr=STDOUT. 247 248 >>> check_output(["/bin/sh", "-c", 249 ... "ls -l non_existent_file ; exit 0"], 250 ... stderr=STDOUT) 251 'ls: non_existent_file: No such file or directory\n' 252 """ 253 254 # Assign the sender object to variable 'test' and remove it from kwargs. 255 test = kwargs.pop('sender', None) 256 257 if 'stdout' in kwargs: 258 raise ValueError('stdout argument not allowed, it will be overridden.') 259 process = Popen(stdout=PIPE, stderr=PIPE, *popenargs, **kwargs) 260 pid = process.pid 261 output, error = process.communicate() 262 retcode = process.poll() 263 264 with recording(test, traceAlways) as sbuf: 265 if isinstance(popenargs, types.StringTypes): 266 args = [popenargs] 267 else: 268 args = list(popenargs) 269 print >> sbuf 270 print >> sbuf, "os command:", args 271 print >> sbuf, "with pid:", pid 272 print >> sbuf, "stdout:", output 273 print >> sbuf, "stderr:", error 274 print >> sbuf, "retcode:", retcode 275 print >> sbuf 276 277 if retcode: 278 cmd = kwargs.get("args") 279 if cmd is None: 280 cmd = popenargs[0] 281 raise CalledProcessError(retcode, cmd) 282 return (output, error) 283 284def getsource_if_available(obj): 285 """ 286 Return the text of the source code for an object if available. Otherwise, 287 a print representation is returned. 288 """ 289 import inspect 290 try: 291 return inspect.getsource(obj) 292 except: 293 return repr(obj) 294 295def builder_module(): 296 return __import__("builder_" + sys.platform) 297 298# 299# Decorators for categorizing test cases. 300# 301 302from functools import wraps 303def python_api_test(func): 304 """Decorate the item as a Python API only test.""" 305 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 306 raise Exception("@python_api_test can only be used to decorate a test method") 307 @wraps(func) 308 def wrapper(self, *args, **kwargs): 309 try: 310 if lldb.dont_do_python_api_test: 311 self.skipTest("python api tests") 312 except AttributeError: 313 pass 314 return func(self, *args, **kwargs) 315 316 # Mark this function as such to separate them from lldb command line tests. 317 wrapper.__python_api_test__ = True 318 return wrapper 319 320def benchmarks_test(func): 321 """Decorate the item as a benchmarks test.""" 322 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 323 raise Exception("@benchmarks_test can only be used to decorate a test method") 324 @wraps(func) 325 def wrapper(self, *args, **kwargs): 326 try: 327 if not lldb.just_do_benchmarks_test: 328 self.skipTest("benchmarks tests") 329 except AttributeError: 330 pass 331 return func(self, *args, **kwargs) 332 333 # Mark this function as such to separate them from the regular tests. 334 wrapper.__benchmarks_test__ = True 335 return wrapper 336 337def dsym_test(func): 338 """Decorate the item as a dsym test.""" 339 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 340 raise Exception("@dsym_test can only be used to decorate a test method") 341 @wraps(func) 342 def wrapper(self, *args, **kwargs): 343 try: 344 if lldb.dont_do_dsym_test: 345 self.skipTest("dsym tests") 346 except AttributeError: 347 pass 348 return func(self, *args, **kwargs) 349 350 # Mark this function as such to separate them from the regular tests. 351 wrapper.__dsym_test__ = True 352 return wrapper 353 354def dwarf_test(func): 355 """Decorate the item as a dwarf test.""" 356 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 357 raise Exception("@dwarf_test can only be used to decorate a test method") 358 @wraps(func) 359 def wrapper(self, *args, **kwargs): 360 try: 361 if lldb.dont_do_dwarf_test: 362 self.skipTest("dwarf tests") 363 except AttributeError: 364 pass 365 return func(self, *args, **kwargs) 366 367 # Mark this function as such to separate them from the regular tests. 368 wrapper.__dwarf_test__ = True 369 return wrapper 370 371def expectedFailureCompiler(func,compiler,bugnumber=None): 372 if callable(bugnumber): 373 @wraps(bugnumber) 374 def expectedFailureCompiler_easy_wrapper(*args, **kwargs): 375 from unittest2 import case 376 self = args[0] 377 test_compiler = self.getCompiler() 378 try: 379 bugnumber(*args, **kwargs) 380 except Exception: 381 if compiler in test_compiler: 382 raise case._ExpectedFailure(sys.exc_info(),None) 383 else: 384 raise 385 if compiler in test_compiler: 386 raise case._UnexpectedSuccess(sys.exc_info(),None) 387 return expectedFailureCompiler_easy_wrapper 388 else: 389 def expectedFailureCompiler_impl(func): 390 @wraps(func) 391 def wrapper(*args, **kwargs): 392 from unittest2 import case 393 self = args[0] 394 test_compiler = self.getCompiler() 395 try: 396 func(*args, **kwargs) 397 except Exception: 398 if compiler in test_compiler: 399 raise case._ExpectedFailure(sys.exc_info(),bugnumber) 400 else: 401 raise 402 if compiler in test_compiler: 403 raise case._UnexpectedSuccess(sys.exc_info(),bugnumber) 404 return wrapper 405 return expectedFailureCompiler_impl 406 407def expectedFailureGcc(func): 408 """Decorate the item as a GCC only expectedFailure.""" 409 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 410 raise Exception("@expectedFailureClang can only be used to decorate a test method") 411 return expectedFailureCompiler(func, "gcc") 412 413def expectedFailureClang(func): 414 """Decorate the item as a Clang only expectedFailure.""" 415 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 416 raise Exception("@expectedFailureClang can only be used to decorate a test method") 417 return expectedFailureCompiler(func, "clang") 418 419def expectedFailurei386(bugnumber=None): 420 if callable(bugnumber): 421 @wraps(bugnumber) 422 def expectedFailurei386_easy_wrapper(*args, **kwargs): 423 from unittest2 import case 424 self = args[0] 425 arch = self.getArchitecture() 426 try: 427 bugnumber(*args, **kwargs) 428 except Exception: 429 if "i386" in arch: 430 raise case._ExpectedFailure(sys.exc_info(),None) 431 else: 432 raise 433 if "i386" in arch: 434 raise case._UnexpectedSuccess(sys.exc_info(),None) 435 return expectedFailurei386_easy_wrapper 436 else: 437 def expectedFailurei386_impl(func): 438 @wraps(func) 439 def wrapper(*args, **kwargs): 440 from unittest2 import case 441 self = args[0] 442 arch = self.getArchitecture() 443 try: 444 func(*args, **kwargs) 445 except Exception: 446 if "i386" in arch: 447 raise case._ExpectedFailure(sys.exc_info(),bugnumber) 448 else: 449 raise 450 if "i386" in arch: 451 raise case._UnexpectedSuccess(sys.exc_info(),bugnumber) 452 return wrapper 453 return expectedFailurei386_impl 454 455def expectedFailureLinux(bugnumber=None): 456 if callable(bugnumber): 457 @wraps(bugnumber) 458 def expectedFailureLinux_easy_wrapper(*args, **kwargs): 459 from unittest2 import case 460 self = args[0] 461 platform = sys.platform 462 try: 463 bugnumber(*args, **kwargs) 464 except Exception: 465 if "linux" in platform: 466 raise case._ExpectedFailure(sys.exc_info(),None) 467 else: 468 raise 469 if "linux" in platform: 470 raise case._UnexpectedSuccess(sys.exc_info(),None) 471 return expectedFailureLinux_easy_wrapper 472 else: 473 def expectedFailureLinux_impl(func): 474 @wraps(func) 475 def wrapper(*args, **kwargs): 476 from unittest2 import case 477 self = args[0] 478 platform = sys.platform 479 try: 480 func(*args, **kwargs) 481 except Exception: 482 if "linux" in platform: 483 raise case._ExpectedFailure(sys.exc_info(),bugnumber) 484 else: 485 raise 486 if "linux" in platform: 487 raise case._UnexpectedSuccess(sys.exc_info(),bugnumber) 488 return wrapper 489 return expectedFailureLinux_impl 490 491def skipOnLinux(func): 492 """Decorate the item to skip tests that should be skipped on Linux.""" 493 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 494 raise Exception("@skipOnLinux can only be used to decorate a test method") 495 @wraps(func) 496 def wrapper(*args, **kwargs): 497 from unittest2 import case 498 self = args[0] 499 platform = sys.platform 500 if "linux" in platform: 501 self.skipTest("skip on linux") 502 else: 503 func(*args, **kwargs) 504 return wrapper 505 506def skipIfGcc(func): 507 """Decorate the item to skip tests that should be skipped if building with gcc .""" 508 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 509 raise Exception("@skipOnLinux can only be used to decorate a test method") 510 @wraps(func) 511 def wrapper(*args, **kwargs): 512 from unittest2 import case 513 self = args[0] 514 compiler = self.getCompiler() 515 if "gcc" in compiler: 516 self.skipTest("skipping because gcc is the test compiler") 517 else: 518 func(*args, **kwargs) 519 return wrapper 520 521 522class Base(unittest2.TestCase): 523 """ 524 Abstract base for performing lldb (see TestBase) or other generic tests (see 525 BenchBase for one example). lldbtest.Base works with the test driver to 526 accomplish things. 527 528 """ 529 530 # The concrete subclass should override this attribute. 531 mydir = None 532 533 # Keep track of the old current working directory. 534 oldcwd = None 535 536 def TraceOn(self): 537 """Returns True if we are in trace mode (tracing detailed test execution).""" 538 return traceAlways 539 540 @classmethod 541 def setUpClass(cls): 542 """ 543 Python unittest framework class setup fixture. 544 Do current directory manipulation. 545 """ 546 547 # Fail fast if 'mydir' attribute is not overridden. 548 if not cls.mydir or len(cls.mydir) == 0: 549 raise Exception("Subclasses must override the 'mydir' attribute.") 550 551 # Save old working directory. 552 cls.oldcwd = os.getcwd() 553 554 # Change current working directory if ${LLDB_TEST} is defined. 555 # See also dotest.py which sets up ${LLDB_TEST}. 556 if ("LLDB_TEST" in os.environ): 557 if traceAlways: 558 print >> sys.stderr, "Change dir to:", os.path.join(os.environ["LLDB_TEST"], cls.mydir) 559 os.chdir(os.path.join(os.environ["LLDB_TEST"], cls.mydir)) 560 561 @classmethod 562 def tearDownClass(cls): 563 """ 564 Python unittest framework class teardown fixture. 565 Do class-wide cleanup. 566 """ 567 568 if doCleanup and not lldb.skip_build_and_cleanup: 569 # First, let's do the platform-specific cleanup. 570 module = builder_module() 571 if not module.cleanup(): 572 raise Exception("Don't know how to do cleanup") 573 574 # Subclass might have specific cleanup function defined. 575 if getattr(cls, "classCleanup", None): 576 if traceAlways: 577 print >> sys.stderr, "Call class-specific cleanup function for class:", cls 578 try: 579 cls.classCleanup() 580 except: 581 exc_type, exc_value, exc_tb = sys.exc_info() 582 traceback.print_exception(exc_type, exc_value, exc_tb) 583 584 # Restore old working directory. 585 if traceAlways: 586 print >> sys.stderr, "Restore dir to:", cls.oldcwd 587 os.chdir(cls.oldcwd) 588 589 @classmethod 590 def skipLongRunningTest(cls): 591 """ 592 By default, we skip long running test case. 593 This can be overridden by passing '-l' to the test driver (dotest.py). 594 """ 595 if "LLDB_SKIP_LONG_RUNNING_TEST" in os.environ and "NO" == os.environ["LLDB_SKIP_LONG_RUNNING_TEST"]: 596 return False 597 else: 598 return True 599 600 def setUp(self): 601 """Fixture for unittest test case setup. 602 603 It works with the test driver to conditionally skip tests and does other 604 initializations.""" 605 #import traceback 606 #traceback.print_stack() 607 608 if "LLDB_EXEC" in os.environ: 609 self.lldbExec = os.environ["LLDB_EXEC"] 610 else: 611 self.lldbExec = None 612 if "LLDB_HERE" in os.environ: 613 self.lldbHere = os.environ["LLDB_HERE"] 614 else: 615 self.lldbHere = None 616 # If we spawn an lldb process for test (via pexpect), do not load the 617 # init file unless told otherwise. 618 if "NO_LLDBINIT" in os.environ and "NO" == os.environ["NO_LLDBINIT"]: 619 self.lldbOption = "" 620 else: 621 self.lldbOption = "--no-lldbinit" 622 623 # Assign the test method name to self.testMethodName. 624 # 625 # For an example of the use of this attribute, look at test/types dir. 626 # There are a bunch of test cases under test/types and we don't want the 627 # module cacheing subsystem to be confused with executable name "a.out" 628 # used for all the test cases. 629 self.testMethodName = self._testMethodName 630 631 # Python API only test is decorated with @python_api_test, 632 # which also sets the "__python_api_test__" attribute of the 633 # function object to True. 634 try: 635 if lldb.just_do_python_api_test: 636 testMethod = getattr(self, self._testMethodName) 637 if getattr(testMethod, "__python_api_test__", False): 638 pass 639 else: 640 self.skipTest("non python api test") 641 except AttributeError: 642 pass 643 644 # Benchmarks test is decorated with @benchmarks_test, 645 # which also sets the "__benchmarks_test__" attribute of the 646 # function object to True. 647 try: 648 if lldb.just_do_benchmarks_test: 649 testMethod = getattr(self, self._testMethodName) 650 if getattr(testMethod, "__benchmarks_test__", False): 651 pass 652 else: 653 self.skipTest("non benchmarks test") 654 except AttributeError: 655 pass 656 657 # This is for the case of directly spawning 'lldb'/'gdb' and interacting 658 # with it using pexpect. 659 self.child = None 660 self.child_prompt = "(lldb) " 661 # If the child is interacting with the embedded script interpreter, 662 # there are two exits required during tear down, first to quit the 663 # embedded script interpreter and second to quit the lldb command 664 # interpreter. 665 self.child_in_script_interpreter = False 666 667 # These are for customized teardown cleanup. 668 self.dict = None 669 self.doTearDownCleanup = False 670 # And in rare cases where there are multiple teardown cleanups. 671 self.dicts = [] 672 self.doTearDownCleanups = False 673 674 # List of spawned subproces.Popen objects 675 self.subprocesses = [] 676 677 # Create a string buffer to record the session info, to be dumped into a 678 # test case specific file if test failure is encountered. 679 self.session = StringIO.StringIO() 680 681 # Optimistically set __errored__, __failed__, __expected__ to False 682 # initially. If the test errored/failed, the session info 683 # (self.session) is then dumped into a session specific file for 684 # diagnosis. 685 self.__errored__ = False 686 self.__failed__ = False 687 self.__expected__ = False 688 # We are also interested in unexpected success. 689 self.__unexpected__ = False 690 # And skipped tests. 691 self.__skipped__ = False 692 693 # See addTearDownHook(self, hook) which allows the client to add a hook 694 # function to be run during tearDown() time. 695 self.hooks = [] 696 697 # See HideStdout(self). 698 self.sys_stdout_hidden = False 699 700 # set environment variable names for finding shared libraries 701 if sys.platform.startswith("darwin"): 702 self.dylibPath = 'DYLD_LIBRARY_PATH' 703 elif sys.platform.startswith("linux") or sys.platform.startswith("freebsd"): 704 self.dylibPath = 'LD_LIBRARY_PATH' 705 706 def runHooks(self, child=None, child_prompt=None, use_cmd_api=False): 707 """Perform the run hooks to bring lldb debugger to the desired state. 708 709 By default, expect a pexpect spawned child and child prompt to be 710 supplied (use_cmd_api=False). If use_cmd_api is true, ignore the child 711 and child prompt and use self.runCmd() to run the hooks one by one. 712 713 Note that child is a process spawned by pexpect.spawn(). If not, your 714 test case is mostly likely going to fail. 715 716 See also dotest.py where lldb.runHooks are processed/populated. 717 """ 718 if not lldb.runHooks: 719 self.skipTest("No runhooks specified for lldb, skip the test") 720 if use_cmd_api: 721 for hook in lldb.runhooks: 722 self.runCmd(hook) 723 else: 724 if not child or not child_prompt: 725 self.fail("Both child and child_prompt need to be defined.") 726 for hook in lldb.runHooks: 727 child.sendline(hook) 728 child.expect_exact(child_prompt) 729 730 def setAsync(self, value): 731 """ Sets async mode to True/False and ensures it is reset after the testcase completes.""" 732 old_async = self.dbg.GetAsync() 733 self.dbg.SetAsync(value) 734 self.addTearDownHook(lambda: self.dbg.SetAsync(old_async)) 735 736 def cleanupSubprocesses(self): 737 # Ensure any subprocesses are cleaned up 738 for p in self.subprocesses: 739 if p.poll() == None: 740 p.terminate() 741 del p 742 del self.subprocesses[:] 743 744 def spawnSubprocess(self, executable, args=[]): 745 """ Creates a subprocess.Popen object with the specified executable and arguments, 746 saves it in self.subprocesses, and returns the object. 747 NOTE: if using this function, ensure you also call: 748 749 self.addTearDownHook(self.cleanupSubprocesses) 750 751 otherwise the test suite will leak processes. 752 """ 753 754 # Don't display the stdout if not in TraceOn() mode. 755 proc = Popen([executable] + args, 756 stdout = open(os.devnull) if not self.TraceOn() else None, 757 stdin = PIPE) 758 self.subprocesses.append(proc) 759 return proc 760 761 def HideStdout(self): 762 """Hide output to stdout from the user. 763 764 During test execution, there might be cases where we don't want to show the 765 standard output to the user. For example, 766 767 self.runCmd(r'''sc print "\n\n\tHello!\n"''') 768 769 tests whether command abbreviation for 'script' works or not. There is no 770 need to show the 'Hello' output to the user as long as the 'script' command 771 succeeds and we are not in TraceOn() mode (see the '-t' option). 772 773 In this case, the test method calls self.HideStdout(self) to redirect the 774 sys.stdout to a null device, and restores the sys.stdout upon teardown. 775 776 Note that you should only call this method at most once during a test case 777 execution. Any subsequent call has no effect at all.""" 778 if self.sys_stdout_hidden: 779 return 780 781 self.sys_stdout_hidden = True 782 old_stdout = sys.stdout 783 sys.stdout = open(os.devnull, 'w') 784 def restore_stdout(): 785 sys.stdout = old_stdout 786 self.addTearDownHook(restore_stdout) 787 788 # ======================================================================= 789 # Methods for customized teardown cleanups as well as execution of hooks. 790 # ======================================================================= 791 792 def setTearDownCleanup(self, dictionary=None): 793 """Register a cleanup action at tearDown() time with a dictinary""" 794 self.dict = dictionary 795 self.doTearDownCleanup = True 796 797 def addTearDownCleanup(self, dictionary): 798 """Add a cleanup action at tearDown() time with a dictinary""" 799 self.dicts.append(dictionary) 800 self.doTearDownCleanups = True 801 802 def addTearDownHook(self, hook): 803 """ 804 Add a function to be run during tearDown() time. 805 806 Hooks are executed in a first come first serve manner. 807 """ 808 if callable(hook): 809 with recording(self, traceAlways) as sbuf: 810 print >> sbuf, "Adding tearDown hook:", getsource_if_available(hook) 811 self.hooks.append(hook) 812 813 def tearDown(self): 814 """Fixture for unittest test case teardown.""" 815 #import traceback 816 #traceback.print_stack() 817 818 # This is for the case of directly spawning 'lldb' and interacting with it 819 # using pexpect. 820 import pexpect 821 if self.child and self.child.isalive(): 822 with recording(self, traceAlways) as sbuf: 823 print >> sbuf, "tearing down the child process...." 824 try: 825 if self.child_in_script_interpreter: 826 self.child.sendline('quit()') 827 self.child.expect_exact(self.child_prompt) 828 self.child.sendline('settings set interpreter.prompt-on-quit false') 829 self.child.sendline('quit') 830 self.child.expect(pexpect.EOF) 831 except ValueError, ExceptionPexpect: 832 # child is already terminated 833 pass 834 835 # Give it one final blow to make sure the child is terminated. 836 self.child.close() 837 838 # Check and run any hook functions. 839 for hook in reversed(self.hooks): 840 with recording(self, traceAlways) as sbuf: 841 print >> sbuf, "Executing tearDown hook:", getsource_if_available(hook) 842 hook() 843 844 del self.hooks 845 846 # Perform registered teardown cleanup. 847 if doCleanup and self.doTearDownCleanup: 848 self.cleanup(dictionary=self.dict) 849 850 # In rare cases where there are multiple teardown cleanups added. 851 if doCleanup and self.doTearDownCleanups: 852 if self.dicts: 853 for dict in reversed(self.dicts): 854 self.cleanup(dictionary=dict) 855 856 # Decide whether to dump the session info. 857 self.dumpSessionInfo() 858 859 # ========================================================= 860 # Various callbacks to allow introspection of test progress 861 # ========================================================= 862 863 def markError(self): 864 """Callback invoked when an error (unexpected exception) errored.""" 865 self.__errored__ = True 866 with recording(self, False) as sbuf: 867 # False because there's no need to write "ERROR" to the stderr twice. 868 # Once by the Python unittest framework, and a second time by us. 869 print >> sbuf, "ERROR" 870 871 def markFailure(self): 872 """Callback invoked when a failure (test assertion failure) occurred.""" 873 self.__failed__ = True 874 with recording(self, False) as sbuf: 875 # False because there's no need to write "FAIL" to the stderr twice. 876 # Once by the Python unittest framework, and a second time by us. 877 print >> sbuf, "FAIL" 878 879 def markExpectedFailure(self,err,bugnumber): 880 """Callback invoked when an expected failure/error occurred.""" 881 self.__expected__ = True 882 with recording(self, False) as sbuf: 883 # False because there's no need to write "expected failure" to the 884 # stderr twice. 885 # Once by the Python unittest framework, and a second time by us. 886 if bugnumber == None: 887 print >> sbuf, "expected failure" 888 else: 889 print >> sbuf, "expected failure (problem id:" + str(bugnumber) + ")" 890 891 def markSkippedTest(self): 892 """Callback invoked when a test is skipped.""" 893 self.__skipped__ = True 894 with recording(self, False) as sbuf: 895 # False because there's no need to write "skipped test" to the 896 # stderr twice. 897 # Once by the Python unittest framework, and a second time by us. 898 print >> sbuf, "skipped test" 899 900 def markUnexpectedSuccess(self, bugnumber): 901 """Callback invoked when an unexpected success occurred.""" 902 self.__unexpected__ = True 903 with recording(self, False) as sbuf: 904 # False because there's no need to write "unexpected success" to the 905 # stderr twice. 906 # Once by the Python unittest framework, and a second time by us. 907 if bugnumber == None: 908 print >> sbuf, "unexpected success" 909 else: 910 print >> sbuf, "unexpected success (problem id:" + str(bugnumber) + ")" 911 912 def dumpSessionInfo(self): 913 """ 914 Dump the debugger interactions leading to a test error/failure. This 915 allows for more convenient postmortem analysis. 916 917 See also LLDBTestResult (dotest.py) which is a singlton class derived 918 from TextTestResult and overwrites addError, addFailure, and 919 addExpectedFailure methods to allow us to to mark the test instance as 920 such. 921 """ 922 923 # We are here because self.tearDown() detected that this test instance 924 # either errored or failed. The lldb.test_result singleton contains 925 # two lists (erros and failures) which get populated by the unittest 926 # framework. Look over there for stack trace information. 927 # 928 # The lists contain 2-tuples of TestCase instances and strings holding 929 # formatted tracebacks. 930 # 931 # See http://docs.python.org/library/unittest.html#unittest.TestResult. 932 if self.__errored__: 933 pairs = lldb.test_result.errors 934 prefix = 'Error' 935 elif self.__failed__: 936 pairs = lldb.test_result.failures 937 prefix = 'Failure' 938 elif self.__expected__: 939 pairs = lldb.test_result.expectedFailures 940 prefix = 'ExpectedFailure' 941 elif self.__skipped__: 942 prefix = 'SkippedTest' 943 elif self.__unexpected__: 944 prefix = "UnexpectedSuccess" 945 else: 946 # Simply return, there's no session info to dump! 947 return 948 949 if not self.__unexpected__ and not self.__skipped__: 950 for test, traceback in pairs: 951 if test is self: 952 print >> self.session, traceback 953 954 testMethod = getattr(self, self._testMethodName) 955 if getattr(testMethod, "__benchmarks_test__", False): 956 benchmarks = True 957 else: 958 benchmarks = False 959 960 # This records the compiler version used for the test. 961 system([self.getCompiler(), "-v"], sender=self) 962 963 dname = os.path.join(os.environ["LLDB_TEST"], 964 os.environ["LLDB_SESSION_DIRNAME"]) 965 if not os.path.isdir(dname): 966 os.mkdir(dname) 967 fname = os.path.join(dname, "%s-%s-%s-%s.log" % (prefix, self.getArchitecture(), "_".join(self.getCompiler().split('/')), self.id())) 968 with open(fname, "w") as f: 969 import datetime 970 print >> f, "Session info generated @", datetime.datetime.now().ctime() 971 print >> f, self.session.getvalue() 972 print >> f, "To rerun this test, issue the following command from the 'test' directory:\n" 973 print >> f, "./dotest.py %s -v %s -f %s.%s" % (self.getRunOptions(), 974 ('+b' if benchmarks else '-t'), 975 self.__class__.__name__, 976 self._testMethodName) 977 978 # ==================================================== 979 # Config. methods supported through a plugin interface 980 # (enables reading of the current test configuration) 981 # ==================================================== 982 983 def getArchitecture(self): 984 """Returns the architecture in effect the test suite is running with.""" 985 module = builder_module() 986 return module.getArchitecture() 987 988 def getCompiler(self): 989 """Returns the compiler in effect the test suite is running with.""" 990 module = builder_module() 991 return module.getCompiler() 992 993 def getRunOptions(self): 994 """Command line option for -A and -C to run this test again, called from 995 self.dumpSessionInfo().""" 996 arch = self.getArchitecture() 997 comp = self.getCompiler() 998 if arch: 999 option_str = "-A " + arch 1000 else: 1001 option_str = "" 1002 if comp: 1003 option_str += " -C " + comp 1004 return option_str 1005 1006 # ================================================== 1007 # Build methods supported through a plugin interface 1008 # ================================================== 1009 1010 def buildDefault(self, architecture=None, compiler=None, dictionary=None, clean=True): 1011 """Platform specific way to build the default binaries.""" 1012 if lldb.skip_build_and_cleanup: 1013 return 1014 module = builder_module() 1015 if not module.buildDefault(self, architecture, compiler, dictionary, clean): 1016 raise Exception("Don't know how to build default binary") 1017 1018 def buildDsym(self, architecture=None, compiler=None, dictionary=None, clean=True): 1019 """Platform specific way to build binaries with dsym info.""" 1020 if lldb.skip_build_and_cleanup: 1021 return 1022 module = builder_module() 1023 if not module.buildDsym(self, architecture, compiler, dictionary, clean): 1024 raise Exception("Don't know how to build binary with dsym") 1025 1026 def buildDwarf(self, architecture=None, compiler=None, dictionary=None, clean=True): 1027 """Platform specific way to build binaries with dwarf maps.""" 1028 if lldb.skip_build_and_cleanup: 1029 return 1030 module = builder_module() 1031 if not module.buildDwarf(self, architecture, compiler, dictionary, clean): 1032 raise Exception("Don't know how to build binary with dwarf") 1033 1034 def cleanup(self, dictionary=None): 1035 """Platform specific way to do cleanup after build.""" 1036 if lldb.skip_build_and_cleanup: 1037 return 1038 module = builder_module() 1039 if not module.cleanup(self, dictionary): 1040 raise Exception("Don't know how to do cleanup with dictionary: "+dictionary) 1041 1042 1043class TestBase(Base): 1044 """ 1045 This abstract base class is meant to be subclassed. It provides default 1046 implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(), 1047 among other things. 1048 1049 Important things for test class writers: 1050 1051 - Overwrite the mydir class attribute, otherwise your test class won't 1052 run. It specifies the relative directory to the top level 'test' so 1053 the test harness can change to the correct working directory before 1054 running your test. 1055 1056 - The setUp method sets up things to facilitate subsequent interactions 1057 with the debugger as part of the test. These include: 1058 - populate the test method name 1059 - create/get a debugger set with synchronous mode (self.dbg) 1060 - get the command interpreter from with the debugger (self.ci) 1061 - create a result object for use with the command interpreter 1062 (self.res) 1063 - plus other stuffs 1064 1065 - The tearDown method tries to perform some necessary cleanup on behalf 1066 of the test to return the debugger to a good state for the next test. 1067 These include: 1068 - execute any tearDown hooks registered by the test method with 1069 TestBase.addTearDownHook(); examples can be found in 1070 settings/TestSettings.py 1071 - kill the inferior process associated with each target, if any, 1072 and, then delete the target from the debugger's target list 1073 - perform build cleanup before running the next test method in the 1074 same test class; examples of registering for this service can be 1075 found in types/TestIntegerTypes.py with the call: 1076 - self.setTearDownCleanup(dictionary=d) 1077 1078 - Similarly setUpClass and tearDownClass perform classwise setup and 1079 teardown fixtures. The tearDownClass method invokes a default build 1080 cleanup for the entire test class; also, subclasses can implement the 1081 classmethod classCleanup(cls) to perform special class cleanup action. 1082 1083 - The instance methods runCmd and expect are used heavily by existing 1084 test cases to send a command to the command interpreter and to perform 1085 string/pattern matching on the output of such command execution. The 1086 expect method also provides a mode to peform string/pattern matching 1087 without running a command. 1088 1089 - The build methods buildDefault, buildDsym, and buildDwarf are used to 1090 build the binaries used during a particular test scenario. A plugin 1091 should be provided for the sys.platform running the test suite. The 1092 Mac OS X implementation is located in plugins/darwin.py. 1093 """ 1094 1095 # Maximum allowed attempts when launching the inferior process. 1096 # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable. 1097 maxLaunchCount = 3; 1098 1099 # Time to wait before the next launching attempt in second(s). 1100 # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable. 1101 timeWaitNextLaunch = 1.0; 1102 1103 def doDelay(self): 1104 """See option -w of dotest.py.""" 1105 if ("LLDB_WAIT_BETWEEN_TEST_CASES" in os.environ and 1106 os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] == 'YES'): 1107 waitTime = 1.0 1108 if "LLDB_TIME_WAIT_BETWEEN_TEST_CASES" in os.environ: 1109 waitTime = float(os.environ["LLDB_TIME_WAIT_BETWEEN_TEST_CASES"]) 1110 time.sleep(waitTime) 1111 1112 # Returns the list of categories to which this test case belongs 1113 # by default, look for a ".categories" file, and read its contents 1114 # if no such file exists, traverse the hierarchy - we guarantee 1115 # a .categories to exist at the top level directory so we do not end up 1116 # looping endlessly - subclasses are free to define their own categories 1117 # in whatever way makes sense to them 1118 def getCategories(self): 1119 import inspect 1120 import os.path 1121 folder = inspect.getfile(self.__class__) 1122 folder = os.path.dirname(folder) 1123 while folder != '/': 1124 categories_file_name = os.path.join(folder,".categories") 1125 if os.path.exists(categories_file_name): 1126 categories_file = open(categories_file_name,'r') 1127 categories = categories_file.readline() 1128 categories_file.close() 1129 categories = str.replace(categories,'\n','') 1130 categories = str.replace(categories,'\r','') 1131 return categories.split(',') 1132 else: 1133 folder = os.path.dirname(folder) 1134 continue 1135 1136 def setUp(self): 1137 #import traceback 1138 #traceback.print_stack() 1139 1140 # Works with the test driver to conditionally skip tests via decorators. 1141 Base.setUp(self) 1142 1143 try: 1144 if lldb.blacklist: 1145 className = self.__class__.__name__ 1146 classAndMethodName = "%s.%s" % (className, self._testMethodName) 1147 if className in lldb.blacklist: 1148 self.skipTest(lldb.blacklist.get(className)) 1149 elif classAndMethodName in lldb.blacklist: 1150 self.skipTest(lldb.blacklist.get(classAndMethodName)) 1151 except AttributeError: 1152 pass 1153 1154 # Insert some delay between successive test cases if specified. 1155 self.doDelay() 1156 1157 if "LLDB_MAX_LAUNCH_COUNT" in os.environ: 1158 self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"]) 1159 1160 if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ: 1161 self.timeWaitNextLaunch = float(os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"]) 1162 1163 # Create the debugger instance if necessary. 1164 try: 1165 self.dbg = lldb.DBG 1166 except AttributeError: 1167 self.dbg = lldb.SBDebugger.Create() 1168 1169 if not self.dbg: 1170 raise Exception('Invalid debugger instance') 1171 1172 # We want our debugger to be synchronous. 1173 self.dbg.SetAsync(False) 1174 1175 # Retrieve the associated command interpreter instance. 1176 self.ci = self.dbg.GetCommandInterpreter() 1177 if not self.ci: 1178 raise Exception('Could not get the command interpreter') 1179 1180 # And the result object. 1181 self.res = lldb.SBCommandReturnObject() 1182 1183 # Run global pre-flight code, if defined via the config file. 1184 if lldb.pre_flight: 1185 lldb.pre_flight(self) 1186 1187 # utility methods that tests can use to access the current objects 1188 def target(self): 1189 if not self.dbg: 1190 raise Exception('Invalid debugger instance') 1191 return self.dbg.GetSelectedTarget() 1192 1193 def process(self): 1194 if not self.dbg: 1195 raise Exception('Invalid debugger instance') 1196 return self.dbg.GetSelectedTarget().GetProcess() 1197 1198 def thread(self): 1199 if not self.dbg: 1200 raise Exception('Invalid debugger instance') 1201 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread() 1202 1203 def frame(self): 1204 if not self.dbg: 1205 raise Exception('Invalid debugger instance') 1206 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() 1207 1208 def tearDown(self): 1209 #import traceback 1210 #traceback.print_stack() 1211 1212 Base.tearDown(self) 1213 1214 # Delete the target(s) from the debugger as a general cleanup step. 1215 # This includes terminating the process for each target, if any. 1216 # We'd like to reuse the debugger for our next test without incurring 1217 # the initialization overhead. 1218 targets = [] 1219 for target in self.dbg: 1220 if target: 1221 targets.append(target) 1222 process = target.GetProcess() 1223 if process: 1224 rc = self.invoke(process, "Kill") 1225 self.assertTrue(rc.Success(), PROCESS_KILLED) 1226 for target in targets: 1227 self.dbg.DeleteTarget(target) 1228 1229 # Run global post-flight code, if defined via the config file. 1230 if lldb.post_flight: 1231 lldb.post_flight(self) 1232 1233 del self.dbg 1234 1235 def switch_to_thread_with_stop_reason(self, stop_reason): 1236 """ 1237 Run the 'thread list' command, and select the thread with stop reason as 1238 'stop_reason'. If no such thread exists, no select action is done. 1239 """ 1240 from lldbutil import stop_reason_to_str 1241 self.runCmd('thread list') 1242 output = self.res.GetOutput() 1243 thread_line_pattern = re.compile("^[ *] thread #([0-9]+):.*stop reason = %s" % 1244 stop_reason_to_str(stop_reason)) 1245 for line in output.splitlines(): 1246 matched = thread_line_pattern.match(line) 1247 if matched: 1248 self.runCmd('thread select %s' % matched.group(1)) 1249 1250 def runCmd(self, cmd, msg=None, check=True, trace=False): 1251 """ 1252 Ask the command interpreter to handle the command and then check its 1253 return status. 1254 """ 1255 # Fail fast if 'cmd' is not meaningful. 1256 if not cmd or len(cmd) == 0: 1257 raise Exception("Bad 'cmd' parameter encountered") 1258 1259 trace = (True if traceAlways else trace) 1260 1261 running = (cmd.startswith("run") or cmd.startswith("process launch")) 1262 1263 for i in range(self.maxLaunchCount if running else 1): 1264 self.ci.HandleCommand(cmd, self.res) 1265 1266 with recording(self, trace) as sbuf: 1267 print >> sbuf, "runCmd:", cmd 1268 if not check: 1269 print >> sbuf, "check of return status not required" 1270 if self.res.Succeeded(): 1271 print >> sbuf, "output:", self.res.GetOutput() 1272 else: 1273 print >> sbuf, "runCmd failed!" 1274 print >> sbuf, self.res.GetError() 1275 1276 if self.res.Succeeded(): 1277 break 1278 elif running: 1279 # For process launch, wait some time before possible next try. 1280 time.sleep(self.timeWaitNextLaunch) 1281 with recording(self, trace) as sbuf: 1282 print >> sbuf, "Command '" + cmd + "' failed!" 1283 1284 if check: 1285 self.assertTrue(self.res.Succeeded(), 1286 msg if msg else CMD_MSG(cmd)) 1287 1288 def match (self, str, patterns, msg=None, trace=False, error=False, matching=True, exe=True): 1289 """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern 1290 1291 Otherwise, all the arguments have the same meanings as for the expect function""" 1292 1293 trace = (True if traceAlways else trace) 1294 1295 if exe: 1296 # First run the command. If we are expecting error, set check=False. 1297 # Pass the assert message along since it provides more semantic info. 1298 self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error) 1299 1300 # Then compare the output against expected strings. 1301 output = self.res.GetError() if error else self.res.GetOutput() 1302 1303 # If error is True, the API client expects the command to fail! 1304 if error: 1305 self.assertFalse(self.res.Succeeded(), 1306 "Command '" + str + "' is expected to fail!") 1307 else: 1308 # No execution required, just compare str against the golden input. 1309 output = str 1310 with recording(self, trace) as sbuf: 1311 print >> sbuf, "looking at:", output 1312 1313 # The heading says either "Expecting" or "Not expecting". 1314 heading = "Expecting" if matching else "Not expecting" 1315 1316 for pattern in patterns: 1317 # Match Objects always have a boolean value of True. 1318 match_object = re.search(pattern, output) 1319 matched = bool(match_object) 1320 with recording(self, trace) as sbuf: 1321 print >> sbuf, "%s pattern: %s" % (heading, pattern) 1322 print >> sbuf, "Matched" if matched else "Not matched" 1323 if matched: 1324 break 1325 1326 self.assertTrue(matched if matching else not matched, 1327 msg if msg else EXP_MSG(str, exe)) 1328 1329 return match_object 1330 1331 def expect(self, str, msg=None, patterns=None, startstr=None, endstr=None, substrs=None, trace=False, error=False, matching=True, exe=True): 1332 """ 1333 Similar to runCmd; with additional expect style output matching ability. 1334 1335 Ask the command interpreter to handle the command and then check its 1336 return status. The 'msg' parameter specifies an informational assert 1337 message. We expect the output from running the command to start with 1338 'startstr', matches the substrings contained in 'substrs', and regexp 1339 matches the patterns contained in 'patterns'. 1340 1341 If the keyword argument error is set to True, it signifies that the API 1342 client is expecting the command to fail. In this case, the error stream 1343 from running the command is retrieved and compared against the golden 1344 input, instead. 1345 1346 If the keyword argument matching is set to False, it signifies that the API 1347 client is expecting the output of the command not to match the golden 1348 input. 1349 1350 Finally, the required argument 'str' represents the lldb command to be 1351 sent to the command interpreter. In case the keyword argument 'exe' is 1352 set to False, the 'str' is treated as a string to be matched/not-matched 1353 against the golden input. 1354 """ 1355 trace = (True if traceAlways else trace) 1356 1357 if exe: 1358 # First run the command. If we are expecting error, set check=False. 1359 # Pass the assert message along since it provides more semantic info. 1360 self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error) 1361 1362 # Then compare the output against expected strings. 1363 output = self.res.GetError() if error else self.res.GetOutput() 1364 1365 # If error is True, the API client expects the command to fail! 1366 if error: 1367 self.assertFalse(self.res.Succeeded(), 1368 "Command '" + str + "' is expected to fail!") 1369 else: 1370 # No execution required, just compare str against the golden input. 1371 if isinstance(str,lldb.SBCommandReturnObject): 1372 output = str.GetOutput() 1373 else: 1374 output = str 1375 with recording(self, trace) as sbuf: 1376 print >> sbuf, "looking at:", output 1377 1378 # The heading says either "Expecting" or "Not expecting". 1379 heading = "Expecting" if matching else "Not expecting" 1380 1381 # Start from the startstr, if specified. 1382 # If there's no startstr, set the initial state appropriately. 1383 matched = output.startswith(startstr) if startstr else (True if matching else False) 1384 1385 if startstr: 1386 with recording(self, trace) as sbuf: 1387 print >> sbuf, "%s start string: %s" % (heading, startstr) 1388 print >> sbuf, "Matched" if matched else "Not matched" 1389 1390 # Look for endstr, if specified. 1391 keepgoing = matched if matching else not matched 1392 if endstr: 1393 matched = output.endswith(endstr) 1394 with recording(self, trace) as sbuf: 1395 print >> sbuf, "%s end string: %s" % (heading, endstr) 1396 print >> sbuf, "Matched" if matched else "Not matched" 1397 1398 # Look for sub strings, if specified. 1399 keepgoing = matched if matching else not matched 1400 if substrs and keepgoing: 1401 for str in substrs: 1402 matched = output.find(str) != -1 1403 with recording(self, trace) as sbuf: 1404 print >> sbuf, "%s sub string: %s" % (heading, str) 1405 print >> sbuf, "Matched" if matched else "Not matched" 1406 keepgoing = matched if matching else not matched 1407 if not keepgoing: 1408 break 1409 1410 # Search for regular expression patterns, if specified. 1411 keepgoing = matched if matching else not matched 1412 if patterns and keepgoing: 1413 for pattern in patterns: 1414 # Match Objects always have a boolean value of True. 1415 matched = bool(re.search(pattern, output)) 1416 with recording(self, trace) as sbuf: 1417 print >> sbuf, "%s pattern: %s" % (heading, pattern) 1418 print >> sbuf, "Matched" if matched else "Not matched" 1419 keepgoing = matched if matching else not matched 1420 if not keepgoing: 1421 break 1422 1423 self.assertTrue(matched if matching else not matched, 1424 msg if msg else EXP_MSG(str, exe)) 1425 1426 def invoke(self, obj, name, trace=False): 1427 """Use reflection to call a method dynamically with no argument.""" 1428 trace = (True if traceAlways else trace) 1429 1430 method = getattr(obj, name) 1431 import inspect 1432 self.assertTrue(inspect.ismethod(method), 1433 name + "is a method name of object: " + str(obj)) 1434 result = method() 1435 with recording(self, trace) as sbuf: 1436 print >> sbuf, str(method) + ":", result 1437 return result 1438 1439 # ================================================= 1440 # Misc. helper methods for debugging test execution 1441 # ================================================= 1442 1443 def DebugSBValue(self, val): 1444 """Debug print a SBValue object, if traceAlways is True.""" 1445 from lldbutil import value_type_to_str 1446 1447 if not traceAlways: 1448 return 1449 1450 err = sys.stderr 1451 err.write(val.GetName() + ":\n") 1452 err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n') 1453 err.write('\t' + "ByteSize -> " + str(val.GetByteSize()) + '\n') 1454 err.write('\t' + "NumChildren -> " + str(val.GetNumChildren()) + '\n') 1455 err.write('\t' + "Value -> " + str(val.GetValue()) + '\n') 1456 err.write('\t' + "ValueAsUnsigned -> " + str(val.GetValueAsUnsigned())+ '\n') 1457 err.write('\t' + "ValueType -> " + value_type_to_str(val.GetValueType()) + '\n') 1458 err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n') 1459 err.write('\t' + "IsPointerType -> " + str(val.TypeIsPointerType()) + '\n') 1460 err.write('\t' + "Location -> " + val.GetLocation() + '\n') 1461 1462 def DebugSBType(self, type): 1463 """Debug print a SBType object, if traceAlways is True.""" 1464 if not traceAlways: 1465 return 1466 1467 err = sys.stderr 1468 err.write(type.GetName() + ":\n") 1469 err.write('\t' + "ByteSize -> " + str(type.GetByteSize()) + '\n') 1470 err.write('\t' + "IsPointerType -> " + str(type.IsPointerType()) + '\n') 1471 err.write('\t' + "IsReferenceType -> " + str(type.IsReferenceType()) + '\n') 1472 1473 def DebugPExpect(self, child): 1474 """Debug the spwaned pexpect object.""" 1475 if not traceAlways: 1476 return 1477 1478 print child 1479 1480 @classmethod 1481 def RemoveTempFile(cls, file): 1482 if os.path.exists(file): 1483 os.remove(file) 1484