lldbtest.py revision 3d4d51cd1bdef32ab61ba9e1de75d5a4f4c1dbed
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 expectedFailureGcc(bugnumber=None): 372 if callable(bugnumber): 373 @wraps(bugnumber) 374 def expectedFailureGcc_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 "gcc" in test_compiler: 382 raise case._ExpectedFailure(sys.exc_info(),None) 383 else: 384 raise 385 if "gcc" in test_compiler: 386 raise case._UnexpectedSuccess(sys.exc_info(),None) 387 return expectedFailureGcc_easy_wrapper 388 else: 389 def expectedFailureGcc_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 "gcc" in test_compiler: 399 raise case._ExpectedFailure(sys.exc_info(),bugnumber) 400 else: 401 raise 402 if "gcc" in test_compiler: 403 raise case._UnexpectedSuccess(sys.exc_info(),bugnumber) 404 return wrapper 405 return expectedFailureGcc_impl 406 407def expectedFailureClang(bugnumber=None): 408 if callable(bugnumber): 409 @wraps(bugnumber) 410 def expectedFailureClang_easy_wrapper(*args, **kwargs): 411 from unittest2 import case 412 self = args[0] 413 test_compiler = self.getCompiler() 414 try: 415 bugnumber(*args, **kwargs) 416 except Exception: 417 if "clang" in test_compiler: 418 raise case._ExpectedFailure(sys.exc_info(),None) 419 else: 420 raise 421 if "clang" in test_compiler: 422 raise case._UnexpectedSuccess(sys.exc_info(),None) 423 return expectedFailureClang_easy_wrapper 424 else: 425 def expectedFailureClang_impl(func): 426 @wraps(func) 427 def wrapper(*args, **kwargs): 428 from unittest2 import case 429 self = args[0] 430 test_compiler = self.getCompiler() 431 try: 432 func(*args, **kwargs) 433 except Exception: 434 if "clang" in test_compiler: 435 raise case._ExpectedFailure(sys.exc_info(),bugnumber) 436 else: 437 raise 438 if "clang" in test_compiler: 439 raise case._UnexpectedSuccess(sys.exc_info(),bugnumber) 440 return wrapper 441 return expectedFailureClang_impl 442 443def expectedFailureIcc(bugnumber=None): 444 if callable(bugnumber): 445 @wraps(bugnumber) 446 def expectedFailureIcc_easy_wrapper(*args, **kwargs): 447 from unittest2 import case 448 self = args[0] 449 test_compiler = self.getCompiler() 450 try: 451 bugnumber(*args, **kwargs) 452 except Exception: 453 if "icc" in test_compiler: 454 raise case._ExpectedFailure(sys.exc_info(),None) 455 else: 456 raise 457 if "icc" in test_compiler: 458 raise case._UnexpectedSuccess(sys.exc_info(),None) 459 return expectedFailureIcc_easy_wrapper 460 else: 461 def expectedFailureIcc_impl(func): 462 @wraps(func) 463 def wrapper(*args, **kwargs): 464 from unittest2 import case 465 self = args[0] 466 test_compiler = self.getCompiler() 467 try: 468 func(*args, **kwargs) 469 except Exception: 470 if "icc" in test_compiler: 471 raise case._ExpectedFailure(sys.exc_info(),bugnumber) 472 else: 473 raise 474 if "icc" in test_compiler: 475 raise case._UnexpectedSuccess(sys.exc_info(),bugnumber) 476 return wrapper 477 return expectedFailureIcc_impl 478 479 480def expectedFailurei386(bugnumber=None): 481 if callable(bugnumber): 482 @wraps(bugnumber) 483 def expectedFailurei386_easy_wrapper(*args, **kwargs): 484 from unittest2 import case 485 self = args[0] 486 arch = self.getArchitecture() 487 try: 488 bugnumber(*args, **kwargs) 489 except Exception: 490 if "i386" in arch: 491 raise case._ExpectedFailure(sys.exc_info(),None) 492 else: 493 raise 494 if "i386" in arch: 495 raise case._UnexpectedSuccess(sys.exc_info(),None) 496 return expectedFailurei386_easy_wrapper 497 else: 498 def expectedFailurei386_impl(func): 499 @wraps(func) 500 def wrapper(*args, **kwargs): 501 from unittest2 import case 502 self = args[0] 503 arch = self.getArchitecture() 504 try: 505 func(*args, **kwargs) 506 except Exception: 507 if "i386" in arch: 508 raise case._ExpectedFailure(sys.exc_info(),bugnumber) 509 else: 510 raise 511 if "i386" in arch: 512 raise case._UnexpectedSuccess(sys.exc_info(),bugnumber) 513 return wrapper 514 return expectedFailurei386_impl 515 516def expectedFailureLinux(bugnumber=None): 517 if callable(bugnumber): 518 @wraps(bugnumber) 519 def expectedFailureLinux_easy_wrapper(*args, **kwargs): 520 from unittest2 import case 521 self = args[0] 522 platform = sys.platform 523 try: 524 bugnumber(*args, **kwargs) 525 except Exception: 526 if "linux" in platform: 527 raise case._ExpectedFailure(sys.exc_info(),None) 528 else: 529 raise 530 if "linux" in platform: 531 raise case._UnexpectedSuccess(sys.exc_info(),None) 532 return expectedFailureLinux_easy_wrapper 533 else: 534 def expectedFailureLinux_impl(func): 535 @wraps(func) 536 def wrapper(*args, **kwargs): 537 from unittest2 import case 538 self = args[0] 539 platform = sys.platform 540 try: 541 func(*args, **kwargs) 542 except Exception: 543 if "linux" in platform: 544 raise case._ExpectedFailure(sys.exc_info(),bugnumber) 545 else: 546 raise 547 if "linux" in platform: 548 raise case._UnexpectedSuccess(sys.exc_info(),bugnumber) 549 return wrapper 550 return expectedFailureLinux_impl 551 552def expectedFailureDarwin(bugnumber=None): 553 if callable(bugnumber): 554 @wraps(bugnumber) 555 def expectedFailureDarwin_easy_wrapper(*args, **kwargs): 556 from unittest2 import case 557 self = args[0] 558 platform = sys.platform 559 try: 560 bugnumber(*args, **kwargs) 561 except Exception: 562 if "darwin" in platform: 563 raise case._ExpectedFailure(sys.exc_info(),None) 564 else: 565 raise 566 if "darwin" in platform: 567 raise case._UnexpectedSuccess(sys.exc_info(),None) 568 return expectedFailureDarwin_easy_wrapper 569 else: 570 def expectedFailureDarwin_impl(func): 571 @wraps(func) 572 def wrapper(*args, **kwargs): 573 from unittest2 import case 574 self = args[0] 575 platform = sys.platform 576 try: 577 func(*args, **kwargs) 578 except Exception: 579 if "darwin" in platform: 580 raise case._ExpectedFailure(sys.exc_info(),bugnumber) 581 else: 582 raise 583 if "darwin" in platform: 584 raise case._UnexpectedSuccess(sys.exc_info(),bugnumber) 585 return wrapper 586 return expectedFailureDarwin_impl 587 588def skipOnLinux(func): 589 """Decorate the item to skip tests that should be skipped on Linux.""" 590 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 591 raise Exception("@skipOnLinux can only be used to decorate a test method") 592 @wraps(func) 593 def wrapper(*args, **kwargs): 594 from unittest2 import case 595 self = args[0] 596 platform = sys.platform 597 if "linux" in platform: 598 self.skipTest("skip on linux") 599 else: 600 func(*args, **kwargs) 601 return wrapper 602 603def skipIfGcc(func): 604 """Decorate the item to skip tests that should be skipped if building with gcc .""" 605 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 606 raise Exception("@skipIfGcc can only be used to decorate a test method") 607 @wraps(func) 608 def wrapper(*args, **kwargs): 609 from unittest2 import case 610 self = args[0] 611 compiler = self.getCompiler() 612 if "gcc" in compiler: 613 self.skipTest("skipping because gcc is the test compiler") 614 else: 615 func(*args, **kwargs) 616 return wrapper 617 618def skipIfIcc(func): 619 """Decorate the item to skip tests that should be skipped if building with icc .""" 620 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 621 raise Exception("@skipIfIcc can only be used to decorate a test method") 622 @wraps(func) 623 def wrapper(*args, **kwargs): 624 from unittest2 import case 625 self = args[0] 626 compiler = self.getCompiler() 627 if "icc" in compiler: 628 self.skipTest("skipping because icc is the test compiler") 629 else: 630 func(*args, **kwargs) 631 return wrapper 632 633def skipIfi386(func): 634 """Decorate the item to skip tests that should be skipped if building 32-bit.""" 635 if isinstance(func, type) and issubclass(func, unittest2.TestCase): 636 raise Exception("@skipIfi386 can only be used to decorate a test method") 637 @wraps(func) 638 def wrapper(*args, **kwargs): 639 from unittest2 import case 640 self = args[0] 641 if "i386" == self.getArchitecture(): 642 self.skipTest("skipping because i386 is not a supported architecture") 643 else: 644 func(*args, **kwargs) 645 return wrapper 646 647 648class Base(unittest2.TestCase): 649 """ 650 Abstract base for performing lldb (see TestBase) or other generic tests (see 651 BenchBase for one example). lldbtest.Base works with the test driver to 652 accomplish things. 653 654 """ 655 656 # The concrete subclass should override this attribute. 657 mydir = None 658 659 # Keep track of the old current working directory. 660 oldcwd = None 661 662 def TraceOn(self): 663 """Returns True if we are in trace mode (tracing detailed test execution).""" 664 return traceAlways 665 666 @classmethod 667 def setUpClass(cls): 668 """ 669 Python unittest framework class setup fixture. 670 Do current directory manipulation. 671 """ 672 673 # Fail fast if 'mydir' attribute is not overridden. 674 if not cls.mydir or len(cls.mydir) == 0: 675 raise Exception("Subclasses must override the 'mydir' attribute.") 676 677 # Save old working directory. 678 cls.oldcwd = os.getcwd() 679 680 # Change current working directory if ${LLDB_TEST} is defined. 681 # See also dotest.py which sets up ${LLDB_TEST}. 682 if ("LLDB_TEST" in os.environ): 683 if traceAlways: 684 print >> sys.stderr, "Change dir to:", os.path.join(os.environ["LLDB_TEST"], cls.mydir) 685 os.chdir(os.path.join(os.environ["LLDB_TEST"], cls.mydir)) 686 687 @classmethod 688 def tearDownClass(cls): 689 """ 690 Python unittest framework class teardown fixture. 691 Do class-wide cleanup. 692 """ 693 694 if doCleanup and not lldb.skip_build_and_cleanup: 695 # First, let's do the platform-specific cleanup. 696 module = builder_module() 697 if not module.cleanup(): 698 raise Exception("Don't know how to do cleanup") 699 700 # Subclass might have specific cleanup function defined. 701 if getattr(cls, "classCleanup", None): 702 if traceAlways: 703 print >> sys.stderr, "Call class-specific cleanup function for class:", cls 704 try: 705 cls.classCleanup() 706 except: 707 exc_type, exc_value, exc_tb = sys.exc_info() 708 traceback.print_exception(exc_type, exc_value, exc_tb) 709 710 # Restore old working directory. 711 if traceAlways: 712 print >> sys.stderr, "Restore dir to:", cls.oldcwd 713 os.chdir(cls.oldcwd) 714 715 @classmethod 716 def skipLongRunningTest(cls): 717 """ 718 By default, we skip long running test case. 719 This can be overridden by passing '-l' to the test driver (dotest.py). 720 """ 721 if "LLDB_SKIP_LONG_RUNNING_TEST" in os.environ and "NO" == os.environ["LLDB_SKIP_LONG_RUNNING_TEST"]: 722 return False 723 else: 724 return True 725 726 def setUp(self): 727 """Fixture for unittest test case setup. 728 729 It works with the test driver to conditionally skip tests and does other 730 initializations.""" 731 #import traceback 732 #traceback.print_stack() 733 734 if "LLDB_EXEC" in os.environ: 735 self.lldbExec = os.environ["LLDB_EXEC"] 736 else: 737 self.lldbExec = None 738 if "LLDB_HERE" in os.environ: 739 self.lldbHere = os.environ["LLDB_HERE"] 740 else: 741 self.lldbHere = None 742 # If we spawn an lldb process for test (via pexpect), do not load the 743 # init file unless told otherwise. 744 if "NO_LLDBINIT" in os.environ and "NO" == os.environ["NO_LLDBINIT"]: 745 self.lldbOption = "" 746 else: 747 self.lldbOption = "--no-lldbinit" 748 749 # Assign the test method name to self.testMethodName. 750 # 751 # For an example of the use of this attribute, look at test/types dir. 752 # There are a bunch of test cases under test/types and we don't want the 753 # module cacheing subsystem to be confused with executable name "a.out" 754 # used for all the test cases. 755 self.testMethodName = self._testMethodName 756 757 # Python API only test is decorated with @python_api_test, 758 # which also sets the "__python_api_test__" attribute of the 759 # function object to True. 760 try: 761 if lldb.just_do_python_api_test: 762 testMethod = getattr(self, self._testMethodName) 763 if getattr(testMethod, "__python_api_test__", False): 764 pass 765 else: 766 self.skipTest("non python api test") 767 except AttributeError: 768 pass 769 770 # Benchmarks test is decorated with @benchmarks_test, 771 # which also sets the "__benchmarks_test__" attribute of the 772 # function object to True. 773 try: 774 if lldb.just_do_benchmarks_test: 775 testMethod = getattr(self, self._testMethodName) 776 if getattr(testMethod, "__benchmarks_test__", False): 777 pass 778 else: 779 self.skipTest("non benchmarks test") 780 except AttributeError: 781 pass 782 783 # This is for the case of directly spawning 'lldb'/'gdb' and interacting 784 # with it using pexpect. 785 self.child = None 786 self.child_prompt = "(lldb) " 787 # If the child is interacting with the embedded script interpreter, 788 # there are two exits required during tear down, first to quit the 789 # embedded script interpreter and second to quit the lldb command 790 # interpreter. 791 self.child_in_script_interpreter = False 792 793 # These are for customized teardown cleanup. 794 self.dict = None 795 self.doTearDownCleanup = False 796 # And in rare cases where there are multiple teardown cleanups. 797 self.dicts = [] 798 self.doTearDownCleanups = False 799 800 # List of spawned subproces.Popen objects 801 self.subprocesses = [] 802 803 # Create a string buffer to record the session info, to be dumped into a 804 # test case specific file if test failure is encountered. 805 self.session = StringIO.StringIO() 806 807 # Optimistically set __errored__, __failed__, __expected__ to False 808 # initially. If the test errored/failed, the session info 809 # (self.session) is then dumped into a session specific file for 810 # diagnosis. 811 self.__errored__ = False 812 self.__failed__ = False 813 self.__expected__ = False 814 # We are also interested in unexpected success. 815 self.__unexpected__ = False 816 # And skipped tests. 817 self.__skipped__ = False 818 819 # See addTearDownHook(self, hook) which allows the client to add a hook 820 # function to be run during tearDown() time. 821 self.hooks = [] 822 823 # See HideStdout(self). 824 self.sys_stdout_hidden = False 825 826 # set environment variable names for finding shared libraries 827 if sys.platform.startswith("darwin"): 828 self.dylibPath = 'DYLD_LIBRARY_PATH' 829 elif sys.platform.startswith("linux") or sys.platform.startswith("freebsd"): 830 self.dylibPath = 'LD_LIBRARY_PATH' 831 832 def runHooks(self, child=None, child_prompt=None, use_cmd_api=False): 833 """Perform the run hooks to bring lldb debugger to the desired state. 834 835 By default, expect a pexpect spawned child and child prompt to be 836 supplied (use_cmd_api=False). If use_cmd_api is true, ignore the child 837 and child prompt and use self.runCmd() to run the hooks one by one. 838 839 Note that child is a process spawned by pexpect.spawn(). If not, your 840 test case is mostly likely going to fail. 841 842 See also dotest.py where lldb.runHooks are processed/populated. 843 """ 844 if not lldb.runHooks: 845 self.skipTest("No runhooks specified for lldb, skip the test") 846 if use_cmd_api: 847 for hook in lldb.runhooks: 848 self.runCmd(hook) 849 else: 850 if not child or not child_prompt: 851 self.fail("Both child and child_prompt need to be defined.") 852 for hook in lldb.runHooks: 853 child.sendline(hook) 854 child.expect_exact(child_prompt) 855 856 def setAsync(self, value): 857 """ Sets async mode to True/False and ensures it is reset after the testcase completes.""" 858 old_async = self.dbg.GetAsync() 859 self.dbg.SetAsync(value) 860 self.addTearDownHook(lambda: self.dbg.SetAsync(old_async)) 861 862 def cleanupSubprocesses(self): 863 # Ensure any subprocesses are cleaned up 864 for p in self.subprocesses: 865 if p.poll() == None: 866 p.terminate() 867 del p 868 del self.subprocesses[:] 869 870 def spawnSubprocess(self, executable, args=[]): 871 """ Creates a subprocess.Popen object with the specified executable and arguments, 872 saves it in self.subprocesses, and returns the object. 873 NOTE: if using this function, ensure you also call: 874 875 self.addTearDownHook(self.cleanupSubprocesses) 876 877 otherwise the test suite will leak processes. 878 """ 879 880 # Don't display the stdout if not in TraceOn() mode. 881 proc = Popen([executable] + args, 882 stdout = open(os.devnull) if not self.TraceOn() else None, 883 stdin = PIPE) 884 self.subprocesses.append(proc) 885 return proc 886 887 def HideStdout(self): 888 """Hide output to stdout from the user. 889 890 During test execution, there might be cases where we don't want to show the 891 standard output to the user. For example, 892 893 self.runCmd(r'''sc print "\n\n\tHello!\n"''') 894 895 tests whether command abbreviation for 'script' works or not. There is no 896 need to show the 'Hello' output to the user as long as the 'script' command 897 succeeds and we are not in TraceOn() mode (see the '-t' option). 898 899 In this case, the test method calls self.HideStdout(self) to redirect the 900 sys.stdout to a null device, and restores the sys.stdout upon teardown. 901 902 Note that you should only call this method at most once during a test case 903 execution. Any subsequent call has no effect at all.""" 904 if self.sys_stdout_hidden: 905 return 906 907 self.sys_stdout_hidden = True 908 old_stdout = sys.stdout 909 sys.stdout = open(os.devnull, 'w') 910 def restore_stdout(): 911 sys.stdout = old_stdout 912 self.addTearDownHook(restore_stdout) 913 914 # ======================================================================= 915 # Methods for customized teardown cleanups as well as execution of hooks. 916 # ======================================================================= 917 918 def setTearDownCleanup(self, dictionary=None): 919 """Register a cleanup action at tearDown() time with a dictinary""" 920 self.dict = dictionary 921 self.doTearDownCleanup = True 922 923 def addTearDownCleanup(self, dictionary): 924 """Add a cleanup action at tearDown() time with a dictinary""" 925 self.dicts.append(dictionary) 926 self.doTearDownCleanups = True 927 928 def addTearDownHook(self, hook): 929 """ 930 Add a function to be run during tearDown() time. 931 932 Hooks are executed in a first come first serve manner. 933 """ 934 if callable(hook): 935 with recording(self, traceAlways) as sbuf: 936 print >> sbuf, "Adding tearDown hook:", getsource_if_available(hook) 937 self.hooks.append(hook) 938 939 def tearDown(self): 940 """Fixture for unittest test case teardown.""" 941 #import traceback 942 #traceback.print_stack() 943 944 # This is for the case of directly spawning 'lldb' and interacting with it 945 # using pexpect. 946 import pexpect 947 if self.child and self.child.isalive(): 948 with recording(self, traceAlways) as sbuf: 949 print >> sbuf, "tearing down the child process...." 950 try: 951 if self.child_in_script_interpreter: 952 self.child.sendline('quit()') 953 self.child.expect_exact(self.child_prompt) 954 self.child.sendline('settings set interpreter.prompt-on-quit false') 955 self.child.sendline('quit') 956 self.child.expect(pexpect.EOF) 957 except ValueError, ExceptionPexpect: 958 # child is already terminated 959 pass 960 961 # Give it one final blow to make sure the child is terminated. 962 self.child.close() 963 964 # Check and run any hook functions. 965 for hook in reversed(self.hooks): 966 with recording(self, traceAlways) as sbuf: 967 print >> sbuf, "Executing tearDown hook:", getsource_if_available(hook) 968 hook() 969 970 del self.hooks 971 972 # Perform registered teardown cleanup. 973 if doCleanup and self.doTearDownCleanup: 974 self.cleanup(dictionary=self.dict) 975 976 # In rare cases where there are multiple teardown cleanups added. 977 if doCleanup and self.doTearDownCleanups: 978 if self.dicts: 979 for dict in reversed(self.dicts): 980 self.cleanup(dictionary=dict) 981 982 # Decide whether to dump the session info. 983 self.dumpSessionInfo() 984 985 # ========================================================= 986 # Various callbacks to allow introspection of test progress 987 # ========================================================= 988 989 def markError(self): 990 """Callback invoked when an error (unexpected exception) errored.""" 991 self.__errored__ = True 992 with recording(self, False) as sbuf: 993 # False because there's no need to write "ERROR" to the stderr twice. 994 # Once by the Python unittest framework, and a second time by us. 995 print >> sbuf, "ERROR" 996 997 def markFailure(self): 998 """Callback invoked when a failure (test assertion failure) occurred.""" 999 self.__failed__ = True 1000 with recording(self, False) as sbuf: 1001 # False because there's no need to write "FAIL" to the stderr twice. 1002 # Once by the Python unittest framework, and a second time by us. 1003 print >> sbuf, "FAIL" 1004 1005 def markExpectedFailure(self,err,bugnumber): 1006 """Callback invoked when an expected failure/error occurred.""" 1007 self.__expected__ = True 1008 with recording(self, False) as sbuf: 1009 # False because there's no need to write "expected failure" to the 1010 # stderr twice. 1011 # Once by the Python unittest framework, and a second time by us. 1012 if bugnumber == None: 1013 print >> sbuf, "expected failure" 1014 else: 1015 print >> sbuf, "expected failure (problem id:" + str(bugnumber) + ")" 1016 1017 def markSkippedTest(self): 1018 """Callback invoked when a test is skipped.""" 1019 self.__skipped__ = True 1020 with recording(self, False) as sbuf: 1021 # False because there's no need to write "skipped test" to the 1022 # stderr twice. 1023 # Once by the Python unittest framework, and a second time by us. 1024 print >> sbuf, "skipped test" 1025 1026 def markUnexpectedSuccess(self, bugnumber): 1027 """Callback invoked when an unexpected success occurred.""" 1028 self.__unexpected__ = True 1029 with recording(self, False) as sbuf: 1030 # False because there's no need to write "unexpected success" to the 1031 # stderr twice. 1032 # Once by the Python unittest framework, and a second time by us. 1033 if bugnumber == None: 1034 print >> sbuf, "unexpected success" 1035 else: 1036 print >> sbuf, "unexpected success (problem id:" + str(bugnumber) + ")" 1037 1038 def dumpSessionInfo(self): 1039 """ 1040 Dump the debugger interactions leading to a test error/failure. This 1041 allows for more convenient postmortem analysis. 1042 1043 See also LLDBTestResult (dotest.py) which is a singlton class derived 1044 from TextTestResult and overwrites addError, addFailure, and 1045 addExpectedFailure methods to allow us to to mark the test instance as 1046 such. 1047 """ 1048 1049 # We are here because self.tearDown() detected that this test instance 1050 # either errored or failed. The lldb.test_result singleton contains 1051 # two lists (erros and failures) which get populated by the unittest 1052 # framework. Look over there for stack trace information. 1053 # 1054 # The lists contain 2-tuples of TestCase instances and strings holding 1055 # formatted tracebacks. 1056 # 1057 # See http://docs.python.org/library/unittest.html#unittest.TestResult. 1058 if self.__errored__: 1059 pairs = lldb.test_result.errors 1060 prefix = 'Error' 1061 elif self.__failed__: 1062 pairs = lldb.test_result.failures 1063 prefix = 'Failure' 1064 elif self.__expected__: 1065 pairs = lldb.test_result.expectedFailures 1066 prefix = 'ExpectedFailure' 1067 elif self.__skipped__: 1068 prefix = 'SkippedTest' 1069 elif self.__unexpected__: 1070 prefix = "UnexpectedSuccess" 1071 else: 1072 # Simply return, there's no session info to dump! 1073 return 1074 1075 if not self.__unexpected__ and not self.__skipped__: 1076 for test, traceback in pairs: 1077 if test is self: 1078 print >> self.session, traceback 1079 1080 testMethod = getattr(self, self._testMethodName) 1081 if getattr(testMethod, "__benchmarks_test__", False): 1082 benchmarks = True 1083 else: 1084 benchmarks = False 1085 1086 # This records the compiler version used for the test. 1087 system([self.getCompiler(), "-v"], sender=self) 1088 1089 dname = os.path.join(os.environ["LLDB_TEST"], 1090 os.environ["LLDB_SESSION_DIRNAME"]) 1091 if not os.path.isdir(dname): 1092 os.mkdir(dname) 1093 fname = os.path.join(dname, "%s-%s-%s-%s.log" % (prefix, self.getArchitecture(), "_".join(self.getCompiler().split('/')), self.id())) 1094 with open(fname, "w") as f: 1095 import datetime 1096 print >> f, "Session info generated @", datetime.datetime.now().ctime() 1097 print >> f, self.session.getvalue() 1098 print >> f, "To rerun this test, issue the following command from the 'test' directory:\n" 1099 print >> f, "./dotest.py %s -v %s -f %s.%s" % (self.getRunOptions(), 1100 ('+b' if benchmarks else '-t'), 1101 self.__class__.__name__, 1102 self._testMethodName) 1103 1104 # ==================================================== 1105 # Config. methods supported through a plugin interface 1106 # (enables reading of the current test configuration) 1107 # ==================================================== 1108 1109 def getArchitecture(self): 1110 """Returns the architecture in effect the test suite is running with.""" 1111 module = builder_module() 1112 return module.getArchitecture() 1113 1114 def getCompiler(self): 1115 """Returns the compiler in effect the test suite is running with.""" 1116 module = builder_module() 1117 return module.getCompiler() 1118 1119 def getCompilerVersion(self): 1120 """ Returns a string that represents the compiler version. 1121 Supports: llvm, clang. 1122 """ 1123 from lldbutil import which 1124 version = 'unknown' 1125 1126 compiler = self.getCompiler() 1127 version_output = system([which(compiler), "-v"])[1] 1128 for line in version_output.split(os.linesep): 1129 m = re.search('version ([0-9\.]+)', line) 1130 if m: 1131 version = m.group(1) 1132 return version 1133 1134 def getRunOptions(self): 1135 """Command line option for -A and -C to run this test again, called from 1136 self.dumpSessionInfo().""" 1137 arch = self.getArchitecture() 1138 comp = self.getCompiler() 1139 if arch: 1140 option_str = "-A " + arch 1141 else: 1142 option_str = "" 1143 if comp: 1144 option_str += " -C " + comp 1145 return option_str 1146 1147 # ================================================== 1148 # Build methods supported through a plugin interface 1149 # ================================================== 1150 1151 def buildDriver(self, sources, exe_name): 1152 """ Platform-specific way to build a program that links with LLDB (via the liblldb.so 1153 or LLDB.framework). 1154 """ 1155 if "gcc" in self.getCompiler() and "4.6" in self.getCompilerVersion(): 1156 stdflag = "-std=c++0x" 1157 else: 1158 stdflag = "-std=c++11" 1159 1160 if sys.platform.startswith("darwin"): 1161 dsym = os.path.join(self.lib_dir, 'LLDB.framework', 'LLDB') 1162 d = {'CXX_SOURCES' : sources, 1163 'EXE' : exe_name, 1164 'CFLAGS_EXTRAS' : "%s -stdlib=libc++" % stdflag, 1165 'FRAMEWORK_INCLUDES' : "-F%s" % self.lib_dir, 1166 'LD_EXTRAS' : dsym, 1167 } 1168 elif sys.platform.startswith("linux") or os.environ.get('LLDB_BUILD_TYPE') == 'Makefile': 1169 d = {'CXX_SOURCES' : sources, 1170 'EXE' : exe_name, 1171 'CFLAGS_EXTRAS' : "%s -I%s" % (stdflag, os.path.join(os.environ["LLDB_SRC"], "include")), 1172 'LD_EXTRAS' : "-L%s -llldb" % self.lib_dir} 1173 if self.TraceOn(): 1174 print "Building LLDB Driver (%s) from sources %s" % (exe_name, sources) 1175 1176 self.buildDefault(dictionary=d) 1177 1178 def buildProgram(self, sources, exe_name): 1179 """ Platform specific way to build an executable from C/C++ sources. """ 1180 d = {'CXX_SOURCES' : sources, 1181 'EXE' : exe_name} 1182 self.buildDefault(dictionary=d) 1183 1184 def buildDefault(self, architecture=None, compiler=None, dictionary=None, clean=True): 1185 """Platform specific way to build the default binaries.""" 1186 if lldb.skip_build_and_cleanup: 1187 return 1188 module = builder_module() 1189 if not module.buildDefault(self, architecture, compiler, dictionary, clean): 1190 raise Exception("Don't know how to build default binary") 1191 1192 def buildDsym(self, architecture=None, compiler=None, dictionary=None, clean=True): 1193 """Platform specific way to build binaries with dsym info.""" 1194 if lldb.skip_build_and_cleanup: 1195 return 1196 module = builder_module() 1197 if not module.buildDsym(self, architecture, compiler, dictionary, clean): 1198 raise Exception("Don't know how to build binary with dsym") 1199 1200 def buildDwarf(self, architecture=None, compiler=None, dictionary=None, clean=True): 1201 """Platform specific way to build binaries with dwarf maps.""" 1202 if lldb.skip_build_and_cleanup: 1203 return 1204 module = builder_module() 1205 if not module.buildDwarf(self, architecture, compiler, dictionary, clean): 1206 raise Exception("Don't know how to build binary with dwarf") 1207 1208 def cleanup(self, dictionary=None): 1209 """Platform specific way to do cleanup after build.""" 1210 if lldb.skip_build_and_cleanup: 1211 return 1212 module = builder_module() 1213 if not module.cleanup(self, dictionary): 1214 raise Exception("Don't know how to do cleanup with dictionary: "+dictionary) 1215 1216 def getLLDBLibraryEnvVal(self): 1217 """ Returns the path that the OS-specific library search environment variable 1218 (self.dylibPath) should be set to in order for a program to find the LLDB 1219 library. If an environment variable named self.dylibPath is already set, 1220 the new path is appended to it and returned. 1221 """ 1222 existing_library_path = os.environ[self.dylibPath] if self.dylibPath in os.environ else None 1223 if existing_library_path: 1224 return "%s:%s" % (existing_library_path, self.lib_dir) 1225 elif sys.platform.startswith("darwin"): 1226 return os.path.join(self.lib_dir, 'LLDB.framework') 1227 else: 1228 return self.lib_dir 1229 1230class TestBase(Base): 1231 """ 1232 This abstract base class is meant to be subclassed. It provides default 1233 implementations for setUpClass(), tearDownClass(), setUp(), and tearDown(), 1234 among other things. 1235 1236 Important things for test class writers: 1237 1238 - Overwrite the mydir class attribute, otherwise your test class won't 1239 run. It specifies the relative directory to the top level 'test' so 1240 the test harness can change to the correct working directory before 1241 running your test. 1242 1243 - The setUp method sets up things to facilitate subsequent interactions 1244 with the debugger as part of the test. These include: 1245 - populate the test method name 1246 - create/get a debugger set with synchronous mode (self.dbg) 1247 - get the command interpreter from with the debugger (self.ci) 1248 - create a result object for use with the command interpreter 1249 (self.res) 1250 - plus other stuffs 1251 1252 - The tearDown method tries to perform some necessary cleanup on behalf 1253 of the test to return the debugger to a good state for the next test. 1254 These include: 1255 - execute any tearDown hooks registered by the test method with 1256 TestBase.addTearDownHook(); examples can be found in 1257 settings/TestSettings.py 1258 - kill the inferior process associated with each target, if any, 1259 and, then delete the target from the debugger's target list 1260 - perform build cleanup before running the next test method in the 1261 same test class; examples of registering for this service can be 1262 found in types/TestIntegerTypes.py with the call: 1263 - self.setTearDownCleanup(dictionary=d) 1264 1265 - Similarly setUpClass and tearDownClass perform classwise setup and 1266 teardown fixtures. The tearDownClass method invokes a default build 1267 cleanup for the entire test class; also, subclasses can implement the 1268 classmethod classCleanup(cls) to perform special class cleanup action. 1269 1270 - The instance methods runCmd and expect are used heavily by existing 1271 test cases to send a command to the command interpreter and to perform 1272 string/pattern matching on the output of such command execution. The 1273 expect method also provides a mode to peform string/pattern matching 1274 without running a command. 1275 1276 - The build methods buildDefault, buildDsym, and buildDwarf are used to 1277 build the binaries used during a particular test scenario. A plugin 1278 should be provided for the sys.platform running the test suite. The 1279 Mac OS X implementation is located in plugins/darwin.py. 1280 """ 1281 1282 # Maximum allowed attempts when launching the inferior process. 1283 # Can be overridden by the LLDB_MAX_LAUNCH_COUNT environment variable. 1284 maxLaunchCount = 3; 1285 1286 # Time to wait before the next launching attempt in second(s). 1287 # Can be overridden by the LLDB_TIME_WAIT_NEXT_LAUNCH environment variable. 1288 timeWaitNextLaunch = 1.0; 1289 1290 def doDelay(self): 1291 """See option -w of dotest.py.""" 1292 if ("LLDB_WAIT_BETWEEN_TEST_CASES" in os.environ and 1293 os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] == 'YES'): 1294 waitTime = 1.0 1295 if "LLDB_TIME_WAIT_BETWEEN_TEST_CASES" in os.environ: 1296 waitTime = float(os.environ["LLDB_TIME_WAIT_BETWEEN_TEST_CASES"]) 1297 time.sleep(waitTime) 1298 1299 # Returns the list of categories to which this test case belongs 1300 # by default, look for a ".categories" file, and read its contents 1301 # if no such file exists, traverse the hierarchy - we guarantee 1302 # a .categories to exist at the top level directory so we do not end up 1303 # looping endlessly - subclasses are free to define their own categories 1304 # in whatever way makes sense to them 1305 def getCategories(self): 1306 import inspect 1307 import os.path 1308 folder = inspect.getfile(self.__class__) 1309 folder = os.path.dirname(folder) 1310 while folder != '/': 1311 categories_file_name = os.path.join(folder,".categories") 1312 if os.path.exists(categories_file_name): 1313 categories_file = open(categories_file_name,'r') 1314 categories = categories_file.readline() 1315 categories_file.close() 1316 categories = str.replace(categories,'\n','') 1317 categories = str.replace(categories,'\r','') 1318 return categories.split(',') 1319 else: 1320 folder = os.path.dirname(folder) 1321 continue 1322 1323 def setUp(self): 1324 #import traceback 1325 #traceback.print_stack() 1326 1327 # Works with the test driver to conditionally skip tests via decorators. 1328 Base.setUp(self) 1329 1330 try: 1331 if lldb.blacklist: 1332 className = self.__class__.__name__ 1333 classAndMethodName = "%s.%s" % (className, self._testMethodName) 1334 if className in lldb.blacklist: 1335 self.skipTest(lldb.blacklist.get(className)) 1336 elif classAndMethodName in lldb.blacklist: 1337 self.skipTest(lldb.blacklist.get(classAndMethodName)) 1338 except AttributeError: 1339 pass 1340 1341 # Insert some delay between successive test cases if specified. 1342 self.doDelay() 1343 1344 if "LLDB_MAX_LAUNCH_COUNT" in os.environ: 1345 self.maxLaunchCount = int(os.environ["LLDB_MAX_LAUNCH_COUNT"]) 1346 1347 if "LLDB_TIME_WAIT_NEXT_LAUNCH" in os.environ: 1348 self.timeWaitNextLaunch = float(os.environ["LLDB_TIME_WAIT_NEXT_LAUNCH"]) 1349 1350 # Create the debugger instance if necessary. 1351 try: 1352 self.dbg = lldb.DBG 1353 except AttributeError: 1354 self.dbg = lldb.SBDebugger.Create() 1355 1356 if not self.dbg: 1357 raise Exception('Invalid debugger instance') 1358 1359 # We want our debugger to be synchronous. 1360 self.dbg.SetAsync(False) 1361 1362 # Retrieve the associated command interpreter instance. 1363 self.ci = self.dbg.GetCommandInterpreter() 1364 if not self.ci: 1365 raise Exception('Could not get the command interpreter') 1366 1367 # And the result object. 1368 self.res = lldb.SBCommandReturnObject() 1369 1370 # Run global pre-flight code, if defined via the config file. 1371 if lldb.pre_flight: 1372 lldb.pre_flight(self) 1373 1374 # utility methods that tests can use to access the current objects 1375 def target(self): 1376 if not self.dbg: 1377 raise Exception('Invalid debugger instance') 1378 return self.dbg.GetSelectedTarget() 1379 1380 def process(self): 1381 if not self.dbg: 1382 raise Exception('Invalid debugger instance') 1383 return self.dbg.GetSelectedTarget().GetProcess() 1384 1385 def thread(self): 1386 if not self.dbg: 1387 raise Exception('Invalid debugger instance') 1388 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread() 1389 1390 def frame(self): 1391 if not self.dbg: 1392 raise Exception('Invalid debugger instance') 1393 return self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame() 1394 1395 def tearDown(self): 1396 #import traceback 1397 #traceback.print_stack() 1398 1399 Base.tearDown(self) 1400 1401 # Delete the target(s) from the debugger as a general cleanup step. 1402 # This includes terminating the process for each target, if any. 1403 # We'd like to reuse the debugger for our next test without incurring 1404 # the initialization overhead. 1405 targets = [] 1406 for target in self.dbg: 1407 if target: 1408 targets.append(target) 1409 process = target.GetProcess() 1410 if process: 1411 rc = self.invoke(process, "Kill") 1412 self.assertTrue(rc.Success(), PROCESS_KILLED) 1413 for target in targets: 1414 self.dbg.DeleteTarget(target) 1415 1416 # Run global post-flight code, if defined via the config file. 1417 if lldb.post_flight: 1418 lldb.post_flight(self) 1419 1420 del self.dbg 1421 1422 def switch_to_thread_with_stop_reason(self, stop_reason): 1423 """ 1424 Run the 'thread list' command, and select the thread with stop reason as 1425 'stop_reason'. If no such thread exists, no select action is done. 1426 """ 1427 from lldbutil import stop_reason_to_str 1428 self.runCmd('thread list') 1429 output = self.res.GetOutput() 1430 thread_line_pattern = re.compile("^[ *] thread #([0-9]+):.*stop reason = %s" % 1431 stop_reason_to_str(stop_reason)) 1432 for line in output.splitlines(): 1433 matched = thread_line_pattern.match(line) 1434 if matched: 1435 self.runCmd('thread select %s' % matched.group(1)) 1436 1437 def runCmd(self, cmd, msg=None, check=True, trace=False): 1438 """ 1439 Ask the command interpreter to handle the command and then check its 1440 return status. 1441 """ 1442 # Fail fast if 'cmd' is not meaningful. 1443 if not cmd or len(cmd) == 0: 1444 raise Exception("Bad 'cmd' parameter encountered") 1445 1446 trace = (True if traceAlways else trace) 1447 1448 running = (cmd.startswith("run") or cmd.startswith("process launch")) 1449 1450 for i in range(self.maxLaunchCount if running else 1): 1451 self.ci.HandleCommand(cmd, self.res) 1452 1453 with recording(self, trace) as sbuf: 1454 print >> sbuf, "runCmd:", cmd 1455 if not check: 1456 print >> sbuf, "check of return status not required" 1457 if self.res.Succeeded(): 1458 print >> sbuf, "output:", self.res.GetOutput() 1459 else: 1460 print >> sbuf, "runCmd failed!" 1461 print >> sbuf, self.res.GetError() 1462 1463 if self.res.Succeeded(): 1464 break 1465 elif running: 1466 # For process launch, wait some time before possible next try. 1467 time.sleep(self.timeWaitNextLaunch) 1468 with recording(self, trace) as sbuf: 1469 print >> sbuf, "Command '" + cmd + "' failed!" 1470 1471 if check: 1472 self.assertTrue(self.res.Succeeded(), 1473 msg if msg else CMD_MSG(cmd)) 1474 1475 def match (self, str, patterns, msg=None, trace=False, error=False, matching=True, exe=True): 1476 """run command in str, and match the result against regexp in patterns returning the match object for the first matching pattern 1477 1478 Otherwise, all the arguments have the same meanings as for the expect function""" 1479 1480 trace = (True if traceAlways else trace) 1481 1482 if exe: 1483 # First run the command. If we are expecting error, set check=False. 1484 # Pass the assert message along since it provides more semantic info. 1485 self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error) 1486 1487 # Then compare the output against expected strings. 1488 output = self.res.GetError() if error else self.res.GetOutput() 1489 1490 # If error is True, the API client expects the command to fail! 1491 if error: 1492 self.assertFalse(self.res.Succeeded(), 1493 "Command '" + str + "' is expected to fail!") 1494 else: 1495 # No execution required, just compare str against the golden input. 1496 output = str 1497 with recording(self, trace) as sbuf: 1498 print >> sbuf, "looking at:", output 1499 1500 # The heading says either "Expecting" or "Not expecting". 1501 heading = "Expecting" if matching else "Not expecting" 1502 1503 for pattern in patterns: 1504 # Match Objects always have a boolean value of True. 1505 match_object = re.search(pattern, output) 1506 matched = bool(match_object) 1507 with recording(self, trace) as sbuf: 1508 print >> sbuf, "%s pattern: %s" % (heading, pattern) 1509 print >> sbuf, "Matched" if matched else "Not matched" 1510 if matched: 1511 break 1512 1513 self.assertTrue(matched if matching else not matched, 1514 msg if msg else EXP_MSG(str, exe)) 1515 1516 return match_object 1517 1518 def expect(self, str, msg=None, patterns=None, startstr=None, endstr=None, substrs=None, trace=False, error=False, matching=True, exe=True): 1519 """ 1520 Similar to runCmd; with additional expect style output matching ability. 1521 1522 Ask the command interpreter to handle the command and then check its 1523 return status. The 'msg' parameter specifies an informational assert 1524 message. We expect the output from running the command to start with 1525 'startstr', matches the substrings contained in 'substrs', and regexp 1526 matches the patterns contained in 'patterns'. 1527 1528 If the keyword argument error is set to True, it signifies that the API 1529 client is expecting the command to fail. In this case, the error stream 1530 from running the command is retrieved and compared against the golden 1531 input, instead. 1532 1533 If the keyword argument matching is set to False, it signifies that the API 1534 client is expecting the output of the command not to match the golden 1535 input. 1536 1537 Finally, the required argument 'str' represents the lldb command to be 1538 sent to the command interpreter. In case the keyword argument 'exe' is 1539 set to False, the 'str' is treated as a string to be matched/not-matched 1540 against the golden input. 1541 """ 1542 trace = (True if traceAlways else trace) 1543 1544 if exe: 1545 # First run the command. If we are expecting error, set check=False. 1546 # Pass the assert message along since it provides more semantic info. 1547 self.runCmd(str, msg=msg, trace = (True if trace else False), check = not error) 1548 1549 # Then compare the output against expected strings. 1550 output = self.res.GetError() if error else self.res.GetOutput() 1551 1552 # If error is True, the API client expects the command to fail! 1553 if error: 1554 self.assertFalse(self.res.Succeeded(), 1555 "Command '" + str + "' is expected to fail!") 1556 else: 1557 # No execution required, just compare str against the golden input. 1558 if isinstance(str,lldb.SBCommandReturnObject): 1559 output = str.GetOutput() 1560 else: 1561 output = str 1562 with recording(self, trace) as sbuf: 1563 print >> sbuf, "looking at:", output 1564 1565 # The heading says either "Expecting" or "Not expecting". 1566 heading = "Expecting" if matching else "Not expecting" 1567 1568 # Start from the startstr, if specified. 1569 # If there's no startstr, set the initial state appropriately. 1570 matched = output.startswith(startstr) if startstr else (True if matching else False) 1571 1572 if startstr: 1573 with recording(self, trace) as sbuf: 1574 print >> sbuf, "%s start string: %s" % (heading, startstr) 1575 print >> sbuf, "Matched" if matched else "Not matched" 1576 1577 # Look for endstr, if specified. 1578 keepgoing = matched if matching else not matched 1579 if endstr: 1580 matched = output.endswith(endstr) 1581 with recording(self, trace) as sbuf: 1582 print >> sbuf, "%s end string: %s" % (heading, endstr) 1583 print >> sbuf, "Matched" if matched else "Not matched" 1584 1585 # Look for sub strings, if specified. 1586 keepgoing = matched if matching else not matched 1587 if substrs and keepgoing: 1588 for str in substrs: 1589 matched = output.find(str) != -1 1590 with recording(self, trace) as sbuf: 1591 print >> sbuf, "%s sub string: %s" % (heading, str) 1592 print >> sbuf, "Matched" if matched else "Not matched" 1593 keepgoing = matched if matching else not matched 1594 if not keepgoing: 1595 break 1596 1597 # Search for regular expression patterns, if specified. 1598 keepgoing = matched if matching else not matched 1599 if patterns and keepgoing: 1600 for pattern in patterns: 1601 # Match Objects always have a boolean value of True. 1602 matched = bool(re.search(pattern, output)) 1603 with recording(self, trace) as sbuf: 1604 print >> sbuf, "%s pattern: %s" % (heading, pattern) 1605 print >> sbuf, "Matched" if matched else "Not matched" 1606 keepgoing = matched if matching else not matched 1607 if not keepgoing: 1608 break 1609 1610 self.assertTrue(matched if matching else not matched, 1611 msg if msg else EXP_MSG(str, exe)) 1612 1613 def invoke(self, obj, name, trace=False): 1614 """Use reflection to call a method dynamically with no argument.""" 1615 trace = (True if traceAlways else trace) 1616 1617 method = getattr(obj, name) 1618 import inspect 1619 self.assertTrue(inspect.ismethod(method), 1620 name + "is a method name of object: " + str(obj)) 1621 result = method() 1622 with recording(self, trace) as sbuf: 1623 print >> sbuf, str(method) + ":", result 1624 return result 1625 1626 # ================================================= 1627 # Misc. helper methods for debugging test execution 1628 # ================================================= 1629 1630 def DebugSBValue(self, val): 1631 """Debug print a SBValue object, if traceAlways is True.""" 1632 from lldbutil import value_type_to_str 1633 1634 if not traceAlways: 1635 return 1636 1637 err = sys.stderr 1638 err.write(val.GetName() + ":\n") 1639 err.write('\t' + "TypeName -> " + val.GetTypeName() + '\n') 1640 err.write('\t' + "ByteSize -> " + str(val.GetByteSize()) + '\n') 1641 err.write('\t' + "NumChildren -> " + str(val.GetNumChildren()) + '\n') 1642 err.write('\t' + "Value -> " + str(val.GetValue()) + '\n') 1643 err.write('\t' + "ValueAsUnsigned -> " + str(val.GetValueAsUnsigned())+ '\n') 1644 err.write('\t' + "ValueType -> " + value_type_to_str(val.GetValueType()) + '\n') 1645 err.write('\t' + "Summary -> " + str(val.GetSummary()) + '\n') 1646 err.write('\t' + "IsPointerType -> " + str(val.TypeIsPointerType()) + '\n') 1647 err.write('\t' + "Location -> " + val.GetLocation() + '\n') 1648 1649 def DebugSBType(self, type): 1650 """Debug print a SBType object, if traceAlways is True.""" 1651 if not traceAlways: 1652 return 1653 1654 err = sys.stderr 1655 err.write(type.GetName() + ":\n") 1656 err.write('\t' + "ByteSize -> " + str(type.GetByteSize()) + '\n') 1657 err.write('\t' + "IsPointerType -> " + str(type.IsPointerType()) + '\n') 1658 err.write('\t' + "IsReferenceType -> " + str(type.IsReferenceType()) + '\n') 1659 1660 def DebugPExpect(self, child): 1661 """Debug the spwaned pexpect object.""" 1662 if not traceAlways: 1663 return 1664 1665 print child 1666 1667 @classmethod 1668 def RemoveTempFile(cls, file): 1669 if os.path.exists(file): 1670 os.remove(file) 1671