dotest.py revision a73ad66a4ee96ccc8e6be4a645cd6b9180a72e4b
1#!/usr/bin/env python 2 3""" 4A simple testing framework for lldb using python's unit testing framework. 5 6Tests for lldb are written as python scripts which take advantage of the script 7bridging provided by LLDB.framework to interact with lldb core. 8 9A specific naming pattern is followed by the .py script to be recognized as 10a module which implements a test scenario, namely, Test*.py. 11 12To specify the directories where "Test*.py" python test scripts are located, 13you need to pass in a list of directory names. By default, the current 14working directory is searched if nothing is specified on the command line. 15 16Type: 17 18./dotest.py -h 19 20for available options. 21""" 22 23import os, signal, sys, time 24import subprocess 25import unittest2 26 27def is_exe(fpath): 28 """Returns true if fpath is an executable.""" 29 return os.path.isfile(fpath) and os.access(fpath, os.X_OK) 30 31def which(program): 32 """Returns the full path to a program; None otherwise.""" 33 fpath, fname = os.path.split(program) 34 if fpath: 35 if is_exe(program): 36 return program 37 else: 38 for path in os.environ["PATH"].split(os.pathsep): 39 exe_file = os.path.join(path, program) 40 if is_exe(exe_file): 41 return exe_file 42 return None 43 44class _WritelnDecorator(object): 45 """Used to decorate file-like objects with a handy 'writeln' method""" 46 def __init__(self,stream): 47 self.stream = stream 48 49 def __getattr__(self, attr): 50 if attr in ('stream', '__getstate__'): 51 raise AttributeError(attr) 52 return getattr(self.stream,attr) 53 54 def writeln(self, arg=None): 55 if arg: 56 self.write(arg) 57 self.write('\n') # text-mode streams translate to \r\n if needed 58 59# 60# Global variables: 61# 62 63# The test suite. 64suite = unittest2.TestSuite() 65 66# By default, both command line and Python API tests are performed. 67# Use @python_api_test decorator, defined in lldbtest.py, to mark a test as 68# a Python API test. 69dont_do_python_api_test = False 70 71# By default, both command line and Python API tests are performed. 72just_do_python_api_test = False 73 74# By default, benchmarks tests are not run. 75just_do_benchmarks_test = False 76 77# By default, both dsym and dwarf tests are performed. 78# Use @dsym_test or @dwarf_test decorators, defined in lldbtest.py, to mark a test 79# as a dsym or dwarf test. Use '-N dsym' or '-N dwarf' to exclude dsym or dwarf 80# tests from running. 81dont_do_dsym_test = False 82dont_do_dwarf_test = False 83 84# The blacklist is optional (-b blacklistFile) and allows a central place to skip 85# testclass's and/or testclass.testmethod's. 86blacklist = None 87 88# The dictionary as a result of sourcing blacklistFile. 89blacklistConfig = {} 90 91# The config file is optional. 92configFile = None 93 94# Test suite repeat count. Can be overwritten with '-# count'. 95count = 1 96 97# The dictionary as a result of sourcing configFile. 98config = {} 99# The pre_flight and post_flight functions come from reading a config file. 100pre_flight = None 101post_flight = None 102 103# The 'archs' and 'compilers' can be specified via either command line or configFile, 104# with the command line overriding the configFile. When specified, they should be 105# of the list type. For example, "-A x86_64^i386" => archs=['x86_64', 'i386'] and 106# "-C gcc^clang" => compilers=['gcc', 'clang']. 107archs = ['x86_64', 'i386'] 108compilers = ['clang'] 109 110# The arch might dictate some specific CFLAGS to be passed to the toolchain to build 111# the inferior programs. The global variable cflags_extras provides a hook to do 112# just that. 113cflags_extras = '' 114 115# Delay startup in order for the debugger to attach. 116delay = False 117 118# Dump the Python sys.path variable. Use '-D' to dump sys.path. 119dumpSysPath = False 120 121# Full path of the benchmark executable, as specified by the '-e' option. 122bmExecutable = None 123# The breakpoint specification of bmExecutable, as specified by the '-x' option. 124bmBreakpointSpec = None 125# The benchamrk iteration count, as specified by the '-y' option. 126bmIterationCount = -1 127 128# By default, don't exclude any directories. Use '-X' to add one excluded directory. 129excluded = set(['.svn', '.git']) 130 131# By default, failfast is False. Use '-F' to overwrite it. 132failfast = False 133 134# The filters (testclass.testmethod) used to admit tests into our test suite. 135filters = [] 136 137# The runhooks is a list of lldb commands specifically for the debugger. 138# Use '-k' to specify a runhook. 139runHooks = [] 140 141# If '-g' is specified, the filterspec is not exclusive. If a test module does 142# not contain testclass.testmethod which matches the filterspec, the whole test 143# module is still admitted into our test suite. fs4all flag defaults to True. 144fs4all = True 145 146# Ignore the build search path relative to this script to locate the lldb.py module. 147ignore = False 148 149# By default, we do not skip build and cleanup. Use '-S' option to override. 150skip_build_and_cleanup = False 151 152# By default, we skip long running test case. Use '-l' option to override. 153skip_long_running_test = True 154 155# By default, we print the build dir, lldb version, and svn info. Use '-n' option to 156# turn it off. 157noHeaders = False 158 159# The regular expression pattern to match against eligible filenames as our test cases. 160regexp = None 161 162# By default, tests are executed in place and cleanups are performed afterwards. 163# Use '-r dir' option to relocate the tests and their intermediate files to a 164# different directory and to forgo any cleanups. The directory specified must 165# not exist yet. 166rdir = None 167 168# By default, recorded session info for errored/failed test are dumped into its 169# own file under a session directory named after the timestamp of the test suite 170# run. Use '-s session-dir-name' to specify a specific dir name. 171sdir_name = None 172 173# Set this flag if there is any session info dumped during the test run. 174sdir_has_content = False 175 176# svn_info stores the output from 'svn info lldb.base.dir'. 177svn_info = '' 178 179# The environment variables to unset before running the test cases. 180unsets = [] 181 182# Default verbosity is 0. 183verbose = 0 184 185# Set to True only if verbose is 0 and LLDB trace mode is off. 186progress_bar = False 187 188# By default, search from the script directory. 189testdirs = [ sys.path[0] ] 190 191# Separator string. 192separator = '-' * 70 193 194 195def usage(): 196 print """ 197Usage: dotest.py [option] [args] 198where options: 199-h : print this help message and exit. Add '-v' for more detailed help. 200-A : specify the architecture(s) to launch for the inferior process 201 -A i386 => launch inferior with i386 architecture 202 -A x86_64^i386 => launch inferior with x86_64 and i386 architectures 203-C : specify the compiler(s) used to build the inferior executable 204 -C clang => build debuggee using clang compiler 205 -C /my/full/path/to/clang => specify a full path to the clang binary 206 -C clang^gcc => build debuggee using clang and gcc compilers 207-D : dump the Python sys.path variable 208-E : specify the extra flags to be passed to the toolchain when building the 209 inferior programs to be debugged 210 suggestions: do not lump the -A arch1^arch2 together such that the -E 211 option applies to only one of the architectures 212-N : don't do test cases marked with the @dsym decorator by passing 'dsym' as the option arg, or 213 don't do test cases marked with the @dwarf decorator by passing 'dwarf' as the option arg 214-a : don't do lldb Python API tests 215 use @python_api_test to decorate a test case as lldb Python API test 216+a : just do lldb Python API tests 217 do not specify both '-a' and '+a' at the same time 218+b : just do benchmark tests 219 use @benchmark_test to decorate a test case as such 220-b : read a blacklist file specified after this option 221-c : read a config file specified after this option 222 the architectures and compilers (note the plurals) specified via '-A' and '-C' 223 will override those specified via a config file 224 (see also lldb-trunk/example/test/usage-config) 225-d : delay startup for 10 seconds (in order for the debugger to attach) 226-e : specify the full path of an executable used for benchmark purpose; 227 see also '-x', which provides the breakpoint sepcification 228-F : failfast, stop the test suite on the first error/failure 229-f : specify a filter, which consists of the test class name, a dot, followed by 230 the test method, to only admit such test into the test suite 231 e.g., -f 'ClassTypesTestCase.test_with_dwarf_and_python_api' 232-g : if specified, the filterspec by -f is not exclusive, i.e., if a test module 233 does not match the filterspec (testclass.testmethod), the whole module is 234 still admitted to the test suite 235-i : ignore (don't bailout) if 'lldb.py' module cannot be located in the build 236 tree relative to this script; use PYTHONPATH to locate the module 237-k : specify a runhook, which is an lldb command to be executed by the debugger; 238 '-k' option can occur multiple times, the commands are executed one after the 239 other to bring the debugger to a desired state, so that, for example, further 240 benchmarking can be done 241-l : don't skip long running test 242-n : don't print the headers like build dir, lldb version, and svn info at all 243-p : specify a regexp filename pattern for inclusion in the test suite 244-R : specify a dir to relocate the tests and their intermediate files to; 245 BE WARNED THAT the directory, if exists, will be deleted before running this test driver; 246 no cleanup of intermediate test files is performed in this case 247-r : similar to '-R', 248 except that the directory must not exist before running this test driver 249-S : skip the build and cleanup while running the test 250 use this option with care as you would need to build the inferior(s) by hand 251 and build the executable(s) with the correct name(s) 252 this can be used with '-# n' to stress test certain test cases for n number of 253 times 254-s : specify the name of the dir created to store the session files of tests 255 with errored or failed status; if not specified, the test driver uses the 256 timestamp as the session dir name 257-t : turn on tracing of lldb command and other detailed test executions 258-u : specify an environment variable to unset before running the test cases 259 e.g., -u DYLD_INSERT_LIBRARIES -u MallocScribble' 260-v : do verbose mode of unittest framework (print out each test case invocation) 261-X : exclude a directory from consideration for test discovery 262 -X types => if 'types' appear in the pathname components of a potential testfile 263 it will be ignored 264-x : specify the breakpoint specification for the benchmark executable; 265 see also '-e', which provides the full path of the executable 266-y : specify the iteration count used to collect our benchmarks; an example is 267 the number of times to do 'thread step-over' to measure stepping speed 268 see also '-e' and '-x' options 269-w : insert some wait time (currently 0.5 sec) between consecutive test cases 270-# : Repeat the test suite for a specified number of times 271 272and: 273args : specify a list of directory names to search for test modules named after 274 Test*.py (test discovery) 275 if empty, search from the current working directory, instead 276""" 277 278 if verbose > 0: 279 print """ 280Examples: 281 282This is an example of using the -f option to pinpoint to a specfic test class 283and test method to be run: 284 285$ ./dotest.py -f ClassTypesTestCase.test_with_dsym_and_run_command 286---------------------------------------------------------------------- 287Collected 1 test 288 289test_with_dsym_and_run_command (TestClassTypes.ClassTypesTestCase) 290Test 'frame variable this' when stopped on a class constructor. ... ok 291 292---------------------------------------------------------------------- 293Ran 1 test in 1.396s 294 295OK 296 297And this is an example of using the -p option to run a single file (the filename 298matches the pattern 'ObjC' and it happens to be 'TestObjCMethods.py'): 299 300$ ./dotest.py -v -p ObjC 301---------------------------------------------------------------------- 302Collected 4 tests 303 304test_break_with_dsym (TestObjCMethods.FoundationTestCase) 305Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok 306test_break_with_dwarf (TestObjCMethods.FoundationTestCase) 307Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'. ... ok 308test_data_type_and_expr_with_dsym (TestObjCMethods.FoundationTestCase) 309Lookup objective-c data types and evaluate expressions. ... ok 310test_data_type_and_expr_with_dwarf (TestObjCMethods.FoundationTestCase) 311Lookup objective-c data types and evaluate expressions. ... ok 312 313---------------------------------------------------------------------- 314Ran 4 tests in 16.661s 315 316OK 317 318Running of this script also sets up the LLDB_TEST environment variable so that 319individual test cases can locate their supporting files correctly. The script 320tries to set up Python's search paths for modules by looking at the build tree 321relative to this script. See also the '-i' option in the following example. 322 323Finally, this is an example of using the lldb.py module distributed/installed by 324Xcode4 to run against the tests under the 'forward' directory, and with the '-w' 325option to add some delay between two tests. It uses ARCH=x86_64 to specify that 326as the architecture and CC=clang to specify the compiler used for the test run: 327 328$ PYTHONPATH=/Xcode4/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python ARCH=x86_64 CC=clang ./dotest.py -v -w -i forward 329 330Session logs for test failures/errors will go into directory '2010-11-11-13_56_16' 331---------------------------------------------------------------------- 332Collected 2 tests 333 334test_with_dsym_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase) 335Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok 336test_with_dwarf_and_run_command (TestForwardDeclaration.ForwardDeclarationTestCase) 337Display *bar_ptr when stopped on a function with forward declaration of struct bar. ... ok 338 339---------------------------------------------------------------------- 340Ran 2 tests in 5.659s 341 342OK 343 344The 'Session ...' verbiage is recently introduced (see also the '-s' option) to 345notify the directory containing the session logs for test failures or errors. 346In case there is any test failure/error, a similar message is appended at the 347end of the stderr output for your convenience. 348 349Environment variables related to loggings: 350 351o LLDB_LOG: if defined, specifies the log file pathname for the 'lldb' subsystem 352 with a default option of 'event process' if LLDB_LOG_OPTION is not defined. 353 354o GDB_REMOTE_LOG: if defined, specifies the log file pathname for the 355 'process.gdb-remote' subsystem with a default option of 'packets' if 356 GDB_REMOTE_LOG_OPTION is not defined. 357""" 358 sys.exit(0) 359 360 361def parseOptionsAndInitTestdirs(): 362 """Initialize the list of directories containing our unittest scripts. 363 364 '-h/--help as the first option prints out usage info and exit the program. 365 """ 366 367 global dont_do_python_api_test 368 global just_do_python_api_test 369 global just_do_benchmarks_test 370 global dont_do_dsym_test 371 global dont_do_dwarf_test 372 global blacklist 373 global blacklistConfig 374 global configFile 375 global archs 376 global compilers 377 global count 378 global delay 379 global dumpSysPath 380 global bmExecutable 381 global bmBreakpointSpec 382 global bmIterationCount 383 global failfast 384 global filters 385 global fs4all 386 global ignore 387 global progress_bar 388 global runHooks 389 global skip_build_and_cleanup 390 global skip_long_running_test 391 global noHeaders 392 global regexp 393 global rdir 394 global sdir_name 395 global unsets 396 global verbose 397 global testdirs 398 399 do_help = False 400 401 # Process possible trace and/or verbose flag, among other things. 402 index = 1 403 while index < len(sys.argv): 404 if sys.argv[index].startswith('-') or sys.argv[index].startswith('+'): 405 # We should continue processing... 406 pass 407 else: 408 # End of option processing. 409 break 410 411 if sys.argv[index].find('-h') != -1: 412 index += 1 413 do_help = True 414 elif sys.argv[index].startswith('-A'): 415 # Increment by 1 to fetch the ARCH spec. 416 index += 1 417 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 418 usage() 419 archs = sys.argv[index].split('^') 420 index += 1 421 elif sys.argv[index].startswith('-C'): 422 # Increment by 1 to fetch the CC spec. 423 index += 1 424 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 425 usage() 426 compilers = sys.argv[index].split('^') 427 index += 1 428 elif sys.argv[index].startswith('-D'): 429 dumpSysPath = True 430 index += 1 431 elif sys.argv[index].startswith('-E'): 432 # Increment by 1 to fetch the CFLAGS_EXTRAS spec. 433 index += 1 434 if index >= len(sys.argv): 435 usage() 436 cflags_extras = sys.argv[index] 437 os.environ["CFLAGS_EXTRAS"] = cflags_extras 438 index += 1 439 elif sys.argv[index].startswith('-N'): 440 # Increment by 1 to fetch 'dsym' or 'dwarf'. 441 index += 1 442 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 443 usage() 444 dont_do = sys.argv[index] 445 if dont_do.lower() == 'dsym': 446 dont_do_dsym_test = True 447 elif dont_do.lower() == 'dwarf': 448 dont_do_dwarf_test = True 449 else: 450 print "!!!" 451 print "Warning: -N only accepts either 'dsym' or 'dwarf' as the option arg; you passed in '%s'?" % dont_do 452 print "!!!" 453 index += 1 454 elif sys.argv[index].startswith('-a'): 455 dont_do_python_api_test = True 456 index += 1 457 elif sys.argv[index].startswith('+a'): 458 just_do_python_api_test = True 459 index += 1 460 elif sys.argv[index].startswith('+b'): 461 just_do_benchmarks_test = True 462 index += 1 463 elif sys.argv[index].startswith('-b'): 464 # Increment by 1 to fetch the blacklist file name option argument. 465 index += 1 466 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 467 usage() 468 blacklistFile = sys.argv[index] 469 if not os.path.isfile(blacklistFile): 470 print "Blacklist file:", blacklistFile, "does not exist!" 471 usage() 472 index += 1 473 # Now read the blacklist contents and assign it to blacklist. 474 execfile(blacklistFile, globals(), blacklistConfig) 475 blacklist = blacklistConfig.get('blacklist') 476 elif sys.argv[index].startswith('-c'): 477 # Increment by 1 to fetch the config file name option argument. 478 index += 1 479 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 480 usage() 481 configFile = sys.argv[index] 482 if not os.path.isfile(configFile): 483 print "Config file:", configFile, "does not exist!" 484 usage() 485 index += 1 486 elif sys.argv[index].startswith('-d'): 487 delay = True 488 index += 1 489 elif sys.argv[index].startswith('-e'): 490 # Increment by 1 to fetch the full path of the benchmark executable. 491 index += 1 492 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 493 usage() 494 bmExecutable = sys.argv[index] 495 if not is_exe(bmExecutable): 496 usage() 497 index += 1 498 elif sys.argv[index].startswith('-F'): 499 failfast = True 500 index += 1 501 elif sys.argv[index].startswith('-f'): 502 # Increment by 1 to fetch the filter spec. 503 index += 1 504 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 505 usage() 506 filters.append(sys.argv[index]) 507 index += 1 508 elif sys.argv[index].startswith('-g'): 509 fs4all = False 510 index += 1 511 elif sys.argv[index].startswith('-i'): 512 ignore = True 513 index += 1 514 elif sys.argv[index].startswith('-k'): 515 # Increment by 1 to fetch the runhook lldb command. 516 index += 1 517 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 518 usage() 519 runHooks.append(sys.argv[index]) 520 index += 1 521 elif sys.argv[index].startswith('-l'): 522 skip_long_running_test = False 523 index += 1 524 elif sys.argv[index].startswith('-n'): 525 noHeaders = True 526 index += 1 527 elif sys.argv[index].startswith('-p'): 528 # Increment by 1 to fetch the reg exp pattern argument. 529 index += 1 530 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 531 usage() 532 regexp = sys.argv[index] 533 index += 1 534 elif sys.argv[index].startswith('-R'): 535 # Increment by 1 to fetch the relocated directory argument. 536 index += 1 537 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 538 usage() 539 rdir = os.path.abspath(sys.argv[index]) 540 if os.path.exists(rdir): 541 import shutil 542 print "Removing tree:", rdir 543 shutil.rmtree(rdir) 544 index += 1 545 elif sys.argv[index].startswith('-r'): 546 # Increment by 1 to fetch the relocated directory argument. 547 index += 1 548 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 549 usage() 550 rdir = os.path.abspath(sys.argv[index]) 551 if os.path.exists(rdir): 552 print "Relocated directory:", rdir, "must not exist!" 553 usage() 554 index += 1 555 elif sys.argv[index].startswith('-S'): 556 skip_build_and_cleanup = True 557 index += 1 558 elif sys.argv[index].startswith('-s'): 559 # Increment by 1 to fetch the session dir name. 560 index += 1 561 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 562 usage() 563 sdir_name = sys.argv[index] 564 index += 1 565 elif sys.argv[index].startswith('-t'): 566 os.environ["LLDB_COMMAND_TRACE"] = "YES" 567 index += 1 568 elif sys.argv[index].startswith('-u'): 569 # Increment by 1 to fetch the environment variable to unset. 570 index += 1 571 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 572 usage() 573 unsets.append(sys.argv[index]) 574 index += 1 575 elif sys.argv[index].startswith('-v'): 576 verbose = 2 577 index += 1 578 elif sys.argv[index].startswith('-w'): 579 os.environ["LLDB_WAIT_BETWEEN_TEST_CASES"] = 'YES' 580 index += 1 581 elif sys.argv[index].startswith('-X'): 582 # Increment by 1 to fetch an excluded directory. 583 index += 1 584 if index >= len(sys.argv): 585 usage() 586 excluded.add(sys.argv[index]) 587 index += 1 588 elif sys.argv[index].startswith('-x'): 589 # Increment by 1 to fetch the breakpoint specification of the benchmark executable. 590 index += 1 591 if index >= len(sys.argv): 592 usage() 593 bmBreakpointSpec = sys.argv[index] 594 index += 1 595 elif sys.argv[index].startswith('-y'): 596 # Increment by 1 to fetch the the benchmark iteration count. 597 index += 1 598 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 599 usage() 600 bmIterationCount = int(sys.argv[index]) 601 index += 1 602 elif sys.argv[index].startswith('-#'): 603 # Increment by 1 to fetch the repeat count argument. 604 index += 1 605 if index >= len(sys.argv) or sys.argv[index].startswith('-'): 606 usage() 607 count = int(sys.argv[index]) 608 index += 1 609 else: 610 print "Unknown option: ", sys.argv[index] 611 usage() 612 613 if do_help == True: 614 usage() 615 616 # Do not specify both '-a' and '+a' at the same time. 617 if dont_do_python_api_test and just_do_python_api_test: 618 usage() 619 620 # The simple progress bar is turned on only if verbose == 0 and LLDB_COMMAND_TRACE is not 'YES' 621 if ("LLDB_COMMAND_TRACE" not in os.environ or os.environ["LLDB_COMMAND_TRACE"]!="YES") and verbose==0: 622 progress_bar = True 623 624 # Gather all the dirs passed on the command line. 625 if len(sys.argv) > index: 626 testdirs = map(os.path.abspath, sys.argv[index:]) 627 628 # If '-r dir' is specified, the tests should be run under the relocated 629 # directory. Let's copy the testdirs over. 630 if rdir: 631 from shutil import copytree, ignore_patterns 632 633 tmpdirs = [] 634 orig_testdirs = testdirs[:] 635 for srcdir in testdirs: 636 # For example, /Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/hello_watchpoint 637 # shall be split into ['/Volumes/data/lldb/svn/ToT/', 'functionalities/watchpoint/hello_watchpoint']. 638 # Utilize the relative path to the 'test' directory to make our destination dir path. 639 if ("test"+os.sep) in srcdir: 640 to_split_on = "test"+os.sep 641 else: 642 to_split_on = "test" 643 dstdir = os.path.join(rdir, srcdir.split(to_split_on)[1]) 644 dstdir = dstdir.rstrip(os.sep) 645 # Don't copy the *.pyc and .svn stuffs. 646 copytree(srcdir, dstdir, ignore=ignore_patterns('*.pyc', '.svn')) 647 tmpdirs.append(dstdir) 648 649 # This will be our modified testdirs. 650 testdirs = tmpdirs 651 652 # With '-r dir' specified, there's no cleanup of intermediate test files. 653 os.environ["LLDB_DO_CLEANUP"] = 'NO' 654 655 # If the original testdirs is ['test'], the make directory has already been copied 656 # recursively and is contained within the rdir/test dir. For anything 657 # else, we would need to copy over the make directory and its contents, 658 # so that, os.listdir(rdir) looks like, for example: 659 # 660 # array_types conditional_break make 661 # 662 # where the make directory contains the Makefile.rules file. 663 if len(testdirs) != 1 or os.path.basename(orig_testdirs[0]) != 'test': 664 scriptdir = os.path.dirname(__file__) 665 # Don't copy the .svn stuffs. 666 copytree(os.path.join(scriptdir, 'make'), os.path.join(rdir, 'make'), 667 ignore=ignore_patterns('.svn')) 668 669 #print "testdirs:", testdirs 670 671 # Source the configFile if specified. 672 # The side effect, if any, will be felt from this point on. An example 673 # config file may be these simple two lines: 674 # 675 # sys.stderr = open("/tmp/lldbtest-stderr", "w") 676 # sys.stdout = open("/tmp/lldbtest-stdout", "w") 677 # 678 # which will reassign the two file objects to sys.stderr and sys.stdout, 679 # respectively. 680 # 681 # See also lldb-trunk/example/test/usage-config. 682 global config, pre_flight, post_flight 683 if configFile: 684 # Pass config (a dictionary) as the locals namespace for side-effect. 685 execfile(configFile, globals(), config) 686 print "config:", config 687 if "pre_flight" in config: 688 pre_flight = config["pre_flight"] 689 if not callable(pre_flight): 690 print "fatal error: pre_flight is not callable, exiting." 691 sys.exit(1) 692 if "post_flight" in config: 693 post_flight = config["post_flight"] 694 if not callable(post_flight): 695 print "fatal error: post_flight is not callable, exiting." 696 sys.exit(1) 697 #print "sys.stderr:", sys.stderr 698 #print "sys.stdout:", sys.stdout 699 700 701def setupSysPath(): 702 """ 703 Add LLDB.framework/Resources/Python to the search paths for modules. 704 As a side effect, we also discover the 'lldb' executable and export it here. 705 """ 706 707 global rdir 708 global testdirs 709 global dumpSysPath 710 global noHeaders 711 global svn_info 712 713 # Get the directory containing the current script. 714 if ("DOTEST_PROFILE" in os.environ or "DOTEST_PDB" in os.environ) and "DOTEST_SCRIPT_DIR" in os.environ: 715 scriptPath = os.environ["DOTEST_SCRIPT_DIR"] 716 else: 717 scriptPath = sys.path[0] 718 if not scriptPath.endswith('test'): 719 print "This script expects to reside in lldb's test directory." 720 sys.exit(-1) 721 722 if rdir: 723 # Set up the LLDB_TEST environment variable appropriately, so that the 724 # individual tests can be located relatively. 725 # 726 # See also lldbtest.TestBase.setUpClass(cls). 727 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test': 728 os.environ["LLDB_TEST"] = os.path.join(rdir, 'test') 729 else: 730 os.environ["LLDB_TEST"] = rdir 731 else: 732 os.environ["LLDB_TEST"] = scriptPath 733 734 # Set up the LLDB_SRC environment variable, so that the tests can locate 735 # the LLDB source code. 736 os.environ["LLDB_SRC"] = os.path.join(sys.path[0], os.pardir) 737 738 pluginPath = os.path.join(scriptPath, 'plugins') 739 pexpectPath = os.path.join(scriptPath, 'pexpect-2.4') 740 741 # Append script dir, plugin dir, and pexpect dir to the sys.path. 742 sys.path.append(scriptPath) 743 sys.path.append(pluginPath) 744 sys.path.append(pexpectPath) 745 746 # This is our base name component. 747 base = os.path.abspath(os.path.join(scriptPath, os.pardir)) 748 749 # These are for xcode build directories. 750 xcode3_build_dir = ['build'] 751 xcode4_build_dir = ['build', 'lldb', 'Build', 'Products'] 752 dbg = ['Debug'] 753 rel = ['Release'] 754 bai = ['BuildAndIntegration'] 755 python_resource_dir = ['LLDB.framework', 'Resources', 'Python'] 756 757 # Some of the tests can invoke the 'lldb' command directly. 758 # We'll try to locate the appropriate executable right here. 759 760 # First, you can define an environment variable LLDB_EXEC specifying the 761 # full pathname of the lldb executable. 762 if "LLDB_EXEC" in os.environ and is_exe(os.environ["LLDB_EXEC"]): 763 lldbExec = os.environ["LLDB_EXEC"] 764 else: 765 lldbExec = None 766 767 executable = ['lldb'] 768 dbgExec = os.path.join(base, *(xcode3_build_dir + dbg + executable)) 769 dbgExec2 = os.path.join(base, *(xcode4_build_dir + dbg + executable)) 770 relExec = os.path.join(base, *(xcode3_build_dir + rel + executable)) 771 relExec2 = os.path.join(base, *(xcode4_build_dir + rel + executable)) 772 baiExec = os.path.join(base, *(xcode3_build_dir + bai + executable)) 773 baiExec2 = os.path.join(base, *(xcode4_build_dir + bai + executable)) 774 775 # The 'lldb' executable built here in the source tree. 776 lldbHere = None 777 if is_exe(dbgExec): 778 lldbHere = dbgExec 779 elif is_exe(dbgExec2): 780 lldbHere = dbgExec2 781 elif is_exe(relExec): 782 lldbHere = relExec 783 elif is_exe(relExec2): 784 lldbHere = relExec2 785 elif is_exe(baiExec): 786 lldbHere = baiExec 787 elif is_exe(baiExec2): 788 lldbHere = baiExec2 789 elif lldbExec: 790 lldbHere = lldbExec 791 792 if lldbHere: 793 os.environ["LLDB_HERE"] = lldbHere 794 os.environ["LLDB_BUILD_DIR"] = os.path.split(lldbHere)[0] 795 if not noHeaders: 796 print "LLDB build dir:", os.environ["LLDB_BUILD_DIR"] 797 os.system('%s -v' % lldbHere) 798 799 # One last chance to locate the 'lldb' executable. 800 if not lldbExec: 801 lldbExec = which('lldb') 802 if lldbHere and not lldbExec: 803 lldbExec = lldbHere 804 805 806 if not lldbExec: 807 print "The 'lldb' executable cannot be located. Some of the tests may not be run as a result." 808 else: 809 os.environ["LLDB_EXEC"] = lldbExec 810 #print "The 'lldb' from PATH env variable", lldbExec 811 812 if os.path.isdir(os.path.join(base, '.svn')): 813 pipe = subprocess.Popen(["svn", "info", base], stdout = subprocess.PIPE) 814 svn_info = pipe.stdout.read() 815 elif os.path.isdir(os.path.join(base, '.git')): 816 pipe = subprocess.Popen(["git", "svn", "info", base], stdout = subprocess.PIPE) 817 svn_info = pipe.stdout.read() 818 if not noHeaders: 819 print svn_info 820 821 global ignore 822 823 # The '-i' option is used to skip looking for lldb.py in the build tree. 824 if ignore: 825 return 826 827 dbgPath = os.path.join(base, *(xcode3_build_dir + dbg + python_resource_dir)) 828 dbgPath2 = os.path.join(base, *(xcode4_build_dir + dbg + python_resource_dir)) 829 relPath = os.path.join(base, *(xcode3_build_dir + rel + python_resource_dir)) 830 relPath2 = os.path.join(base, *(xcode4_build_dir + rel + python_resource_dir)) 831 baiPath = os.path.join(base, *(xcode3_build_dir + bai + python_resource_dir)) 832 baiPath2 = os.path.join(base, *(xcode4_build_dir + bai + python_resource_dir)) 833 834 lldbPath = None 835 if os.path.isfile(os.path.join(dbgPath, 'lldb/__init__.py')): 836 lldbPath = dbgPath 837 elif os.path.isfile(os.path.join(dbgPath2, 'lldb/__init__.py')): 838 lldbPath = dbgPath2 839 elif os.path.isfile(os.path.join(relPath, 'lldb/__init__.py')): 840 lldbPath = relPath 841 elif os.path.isfile(os.path.join(relPath2, 'lldb/__init__.py')): 842 lldbPath = relPath2 843 elif os.path.isfile(os.path.join(baiPath, 'lldb/__init__.py')): 844 lldbPath = baiPath 845 elif os.path.isfile(os.path.join(baiPath2, 'lldb/__init__.py')): 846 lldbPath = baiPath2 847 848 if not lldbPath: 849 print 'This script requires lldb.py to be in either ' + dbgPath + ',', 850 print relPath + ', or ' + baiPath 851 sys.exit(-1) 852 853 # This is to locate the lldb.py module. Insert it right after sys.path[0]. 854 sys.path[1:1] = [lldbPath] 855 if dumpSysPath: 856 print "sys.path:", sys.path 857 858 859def doDelay(delta): 860 """Delaying startup for delta-seconds to facilitate debugger attachment.""" 861 def alarm_handler(*args): 862 raise Exception("timeout") 863 864 signal.signal(signal.SIGALRM, alarm_handler) 865 signal.alarm(delta) 866 sys.stdout.write("pid=%d\n" % os.getpid()) 867 sys.stdout.write("Enter RET to proceed (or timeout after %d seconds):" % 868 delta) 869 sys.stdout.flush() 870 try: 871 text = sys.stdin.readline() 872 except: 873 text = "" 874 signal.alarm(0) 875 sys.stdout.write("proceeding...\n") 876 pass 877 878 879def visit(prefix, dir, names): 880 """Visitor function for os.path.walk(path, visit, arg).""" 881 882 global suite 883 global regexp 884 global filters 885 global fs4all 886 global excluded 887 888 if set(dir.split(os.sep)).intersection(excluded): 889 #print "Detected an excluded dir component: %s" % dir 890 return 891 892 for name in names: 893 if os.path.isdir(os.path.join(dir, name)): 894 continue 895 896 if '.py' == os.path.splitext(name)[1] and name.startswith(prefix): 897 # Try to match the regexp pattern, if specified. 898 if regexp: 899 import re 900 if re.search(regexp, name): 901 #print "Filename: '%s' matches pattern: '%s'" % (name, regexp) 902 pass 903 else: 904 #print "Filename: '%s' does not match pattern: '%s'" % (name, regexp) 905 continue 906 907 # We found a match for our test. Add it to the suite. 908 909 # Update the sys.path first. 910 if not sys.path.count(dir): 911 sys.path.insert(0, dir) 912 base = os.path.splitext(name)[0] 913 914 # Thoroughly check the filterspec against the base module and admit 915 # the (base, filterspec) combination only when it makes sense. 916 filterspec = None 917 for filterspec in filters: 918 # Optimistically set the flag to True. 919 filtered = True 920 module = __import__(base) 921 parts = filterspec.split('.') 922 obj = module 923 for part in parts: 924 try: 925 parent, obj = obj, getattr(obj, part) 926 except AttributeError: 927 # The filterspec has failed. 928 filtered = False 929 break 930 931 # If filtered, we have a good filterspec. Add it. 932 if filtered: 933 #print "adding filter spec %s to module %s" % (filterspec, module) 934 suite.addTests( 935 unittest2.defaultTestLoader.loadTestsFromName(filterspec, module)) 936 continue 937 938 # Forgo this module if the (base, filterspec) combo is invalid 939 # and no '-g' option is specified 940 if filters and fs4all and not filtered: 941 continue 942 943 # Add either the filtered test case(s) (which is done before) or the entire test class. 944 if not filterspec or not filtered: 945 # A simple case of just the module name. Also the failover case 946 # from the filterspec branch when the (base, filterspec) combo 947 # doesn't make sense. 948 suite.addTests(unittest2.defaultTestLoader.loadTestsFromName(base)) 949 950 951def lldbLoggings(): 952 """Check and do lldb loggings if necessary.""" 953 954 # Turn on logging for debugging purposes if ${LLDB_LOG} environment variable is 955 # defined. Use ${LLDB_LOG} to specify the log file. 956 ci = lldb.DBG.GetCommandInterpreter() 957 res = lldb.SBCommandReturnObject() 958 if ("LLDB_LOG" in os.environ): 959 if ("LLDB_LOG_OPTION" in os.environ): 960 lldb_log_option = os.environ["LLDB_LOG_OPTION"] 961 else: 962 lldb_log_option = "event process expr state api" 963 ci.HandleCommand( 964 "log enable -n -f " + os.environ["LLDB_LOG"] + " lldb " + lldb_log_option, 965 res) 966 if not res.Succeeded(): 967 raise Exception('log enable failed (check LLDB_LOG env variable.') 968 # Ditto for gdb-remote logging if ${GDB_REMOTE_LOG} environment variable is defined. 969 # Use ${GDB_REMOTE_LOG} to specify the log file. 970 if ("GDB_REMOTE_LOG" in os.environ): 971 if ("GDB_REMOTE_LOG_OPTION" in os.environ): 972 gdb_remote_log_option = os.environ["GDB_REMOTE_LOG_OPTION"] 973 else: 974 gdb_remote_log_option = "packets process" 975 ci.HandleCommand( 976 "log enable -n -f " + os.environ["GDB_REMOTE_LOG"] + " gdb-remote " 977 + gdb_remote_log_option, 978 res) 979 if not res.Succeeded(): 980 raise Exception('log enable failed (check GDB_REMOTE_LOG env variable.') 981 982def getMyCommandLine(): 983 ps = subprocess.Popen(['ps', '-o', "command=CMD", str(os.getpid())], stdout=subprocess.PIPE).communicate()[0] 984 lines = ps.split('\n') 985 cmd_line = lines[1] 986 return cmd_line 987 988# ======================================== # 989# # 990# Execution of the test driver starts here # 991# # 992# ======================================== # 993 994def checkDsymForUUIDIsNotOn(): 995 cmd = ["defaults", "read", "com.apple.DebugSymbols"] 996 pipe = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.STDOUT) 997 cmd_output = pipe.stdout.read() 998 if cmd_output and "DBGFileMappedPaths = " in cmd_output: 999 print "%s =>" % ' '.join(cmd) 1000 print cmd_output 1001 print "Disable automatic lookup and caching of dSYMs before running the test suite!" 1002 print "Exiting..." 1003 sys.exit(0) 1004 1005# On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults 1006# does not exist before proceeding to running the test suite. 1007if sys.platform.startswith("darwin"): 1008 checkDsymForUUIDIsNotOn() 1009 1010# 1011# Start the actions by first parsing the options while setting up the test 1012# directories, followed by setting up the search paths for lldb utilities; 1013# then, we walk the directory trees and collect the tests into our test suite. 1014# 1015parseOptionsAndInitTestdirs() 1016setupSysPath() 1017 1018# 1019# If '-d' is specified, do a delay of 10 seconds for the debugger to attach. 1020# 1021if delay: 1022 doDelay(10) 1023 1024# 1025# If '-l' is specified, do not skip the long running tests. 1026if not skip_long_running_test: 1027 os.environ["LLDB_SKIP_LONG_RUNNING_TEST"] = "NO" 1028 1029# 1030# Walk through the testdirs while collecting tests. 1031# 1032for testdir in testdirs: 1033 os.path.walk(testdir, visit, 'Test') 1034 1035# 1036# Now that we have loaded all the test cases, run the whole test suite. 1037# 1038 1039# For the time being, let's bracket the test runner within the 1040# lldb.SBDebugger.Initialize()/Terminate() pair. 1041import lldb, atexit 1042# Update: the act of importing lldb now executes lldb.SBDebugger.Initialize(), 1043# there's no need to call it a second time. 1044#lldb.SBDebugger.Initialize() 1045atexit.register(lambda: lldb.SBDebugger.Terminate()) 1046 1047# Create a singleton SBDebugger in the lldb namespace. 1048lldb.DBG = lldb.SBDebugger.Create() 1049 1050# Put the blacklist in the lldb namespace, to be used by lldb.TestBase. 1051lldb.blacklist = blacklist 1052 1053# The pre_flight and post_flight come from reading a config file. 1054lldb.pre_flight = pre_flight 1055lldb.post_flight = post_flight 1056def getsource_if_available(obj): 1057 """ 1058 Return the text of the source code for an object if available. Otherwise, 1059 a print representation is returned. 1060 """ 1061 import inspect 1062 try: 1063 return inspect.getsource(obj) 1064 except: 1065 return repr(obj) 1066 1067print "lldb.pre_flight:", getsource_if_available(lldb.pre_flight) 1068print "lldb.post_flight:", getsource_if_available(lldb.post_flight) 1069 1070# Put all these test decorators in the lldb namespace. 1071lldb.dont_do_python_api_test = dont_do_python_api_test 1072lldb.just_do_python_api_test = just_do_python_api_test 1073lldb.just_do_benchmarks_test = just_do_benchmarks_test 1074lldb.dont_do_dsym_test = dont_do_dsym_test 1075lldb.dont_do_dwarf_test = dont_do_dwarf_test 1076 1077# Do we need to skip build and cleanup? 1078lldb.skip_build_and_cleanup = skip_build_and_cleanup 1079 1080# Put bmExecutable, bmBreakpointSpec, and bmIterationCount into the lldb namespace, too. 1081lldb.bmExecutable = bmExecutable 1082lldb.bmBreakpointSpec = bmBreakpointSpec 1083lldb.bmIterationCount = bmIterationCount 1084 1085# And don't forget the runHooks! 1086lldb.runHooks = runHooks 1087 1088# Turn on lldb loggings if necessary. 1089lldbLoggings() 1090 1091# Install the control-c handler. 1092unittest2.signals.installHandler() 1093 1094# If sdir_name is not specified through the '-s sdir_name' option, get a 1095# timestamp string and export it as LLDB_SESSION_DIR environment var. This will 1096# be used when/if we want to dump the session info of individual test cases 1097# later on. 1098# 1099# See also TestBase.dumpSessionInfo() in lldbtest.py. 1100import datetime 1101# The windows platforms don't like ':' in the pathname. 1102timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S") 1103if not sdir_name: 1104 sdir_name = timestamp_started 1105os.environ["LLDB_SESSION_DIRNAME"] = os.path.join(os.getcwd(), sdir_name) 1106 1107if not noHeaders: 1108 sys.stderr.write("\nSession logs for test failures/errors/unexpected successes" 1109 " will go into directory '%s'\n" % sdir_name) 1110 sys.stderr.write("Command invoked: %s\n" % getMyCommandLine()) 1111 1112if not os.path.isdir(sdir_name): 1113 os.mkdir(sdir_name) 1114fname = os.path.join(sdir_name, "TestStarted") 1115with open(fname, "w") as f: 1116 print >> f, "Test started at: %s\n" % timestamp_started 1117 print >> f, svn_info 1118 print >> f, "Command invoked: %s\n" % getMyCommandLine() 1119 1120# 1121# If we have environment variables to unset, do it here before we invoke the test runner. 1122# 1123for env_var in unsets : 1124 if env_var in os.environ: 1125 # From Python Doc: When unsetenv() is supported, deletion of items in os.environ 1126 # is automatically translated into a corresponding call to unsetenv(). 1127 del os.environ[env_var] 1128 #os.unsetenv(env_var) 1129 1130# 1131# Invoke the default TextTestRunner to run the test suite, possibly iterating 1132# over different configurations. 1133# 1134 1135iterArchs = False 1136iterCompilers = False 1137 1138if not archs and "archs" in config: 1139 archs = config["archs"] 1140 1141if isinstance(archs, list) and len(archs) >= 1: 1142 iterArchs = True 1143 1144if not compilers and "compilers" in config: 1145 compilers = config["compilers"] 1146 1147# 1148# Add some intervention here to sanity check that the compilers requested are sane. 1149# If found not to be an executable program, the invalid one is dropped from the list. 1150for i in range(len(compilers)): 1151 c = compilers[i] 1152 if which(c): 1153 continue 1154 else: 1155 if sys.platform.startswith("darwin"): 1156 pipe = subprocess.Popen(['xcrun', '-find', c], stdout = subprocess.PIPE, stderr = subprocess.STDOUT) 1157 cmd_output = pipe.stdout.read() 1158 if cmd_output: 1159 if "not found" in cmd_output: 1160 print "dropping %s from the compilers used" % c 1161 compilers.remove(i) 1162 else: 1163 compilers[i] = cmd_output.split('\n')[0] 1164 print "'xcrun -find %s' returning %s" % (c, compilers[i]) 1165 1166print "compilers=%s" % str(compilers) 1167 1168if not compilers or len(compilers) == 0: 1169 print "No eligible compiler found, exiting." 1170 sys.exit(1) 1171 1172if isinstance(compilers, list) and len(compilers) >= 1: 1173 iterCompilers = True 1174 1175# Make a shallow copy of sys.path, we need to manipulate the search paths later. 1176# This is only necessary if we are relocated and with different configurations. 1177if rdir: 1178 old_sys_path = sys.path[:] 1179# If we iterate on archs or compilers, there is a chance we want to split stderr/stdout. 1180if iterArchs or iterCompilers: 1181 old_stderr = sys.stderr 1182 old_stdout = sys.stdout 1183 new_stderr = None 1184 new_stdout = None 1185 1186# Iterating over all possible architecture and compiler combinations. 1187for ia in range(len(archs) if iterArchs else 1): 1188 archConfig = "" 1189 if iterArchs: 1190 os.environ["ARCH"] = archs[ia] 1191 archConfig = "arch=%s" % archs[ia] 1192 for ic in range(len(compilers) if iterCompilers else 1): 1193 if iterCompilers: 1194 os.environ["CC"] = compilers[ic] 1195 configString = "%s compiler=%s" % (archConfig, compilers[ic]) 1196 else: 1197 configString = archConfig 1198 1199 if iterArchs or iterCompilers: 1200 # Translate ' ' to '-' for pathname component. 1201 from string import maketrans 1202 tbl = maketrans(' ', '-') 1203 configPostfix = configString.translate(tbl) 1204 1205 # Check whether we need to split stderr/stdout into configuration 1206 # specific files. 1207 if old_stderr.name != '<stderr>' and config.get('split_stderr'): 1208 if new_stderr: 1209 new_stderr.close() 1210 new_stderr = open("%s.%s" % (old_stderr.name, configPostfix), "w") 1211 sys.stderr = new_stderr 1212 if old_stdout.name != '<stdout>' and config.get('split_stdout'): 1213 if new_stdout: 1214 new_stdout.close() 1215 new_stdout = open("%s.%s" % (old_stdout.name, configPostfix), "w") 1216 sys.stdout = new_stdout 1217 1218 # If we specified a relocated directory to run the test suite, do 1219 # the extra housekeeping to copy the testdirs to a configStringified 1220 # directory and to update sys.path before invoking the test runner. 1221 # The purpose is to separate the configuration-specific directories 1222 # from each other. 1223 if rdir: 1224 from shutil import copytree, rmtree, ignore_patterns 1225 1226 newrdir = "%s.%s" % (rdir, configPostfix) 1227 1228 # Copy the tree to a new directory with postfix name configPostfix. 1229 if os.path.exists(newrdir): 1230 rmtree(newrdir) 1231 copytree(rdir, newrdir, ignore=ignore_patterns('*.pyc', '*.o', '*.d')) 1232 1233 # Update the LLDB_TEST environment variable to reflect new top 1234 # level test directory. 1235 # 1236 # See also lldbtest.TestBase.setUpClass(cls). 1237 if len(testdirs) == 1 and os.path.basename(testdirs[0]) == 'test': 1238 os.environ["LLDB_TEST"] = os.path.join(newrdir, 'test') 1239 else: 1240 os.environ["LLDB_TEST"] = newrdir 1241 1242 # And update the Python search paths for modules. 1243 sys.path = [x.replace(rdir, newrdir, 1) for x in old_sys_path] 1244 1245 # Output the configuration. 1246 sys.stderr.write("\nConfiguration: " + configString + "\n") 1247 1248 #print "sys.stderr name is", sys.stderr.name 1249 #print "sys.stdout name is", sys.stdout.name 1250 1251 # First, write out the number of collected test cases. 1252 sys.stderr.write(separator + "\n") 1253 sys.stderr.write("Collected %d test%s\n\n" 1254 % (suite.countTestCases(), 1255 suite.countTestCases() != 1 and "s" or "")) 1256 1257 class LLDBTestResult(unittest2.TextTestResult): 1258 """ 1259 Enforce a singleton pattern to allow introspection of test progress. 1260 1261 Overwrite addError(), addFailure(), and addExpectedFailure() methods 1262 to enable each test instance to track its failure/error status. It 1263 is used in the LLDB test framework to emit detailed trace messages 1264 to a log file for easier human inspection of test failres/errors. 1265 """ 1266 __singleton__ = None 1267 __ignore_singleton__ = False 1268 1269 def __init__(self, *args): 1270 if not LLDBTestResult.__ignore_singleton__ and LLDBTestResult.__singleton__: 1271 raise Exception("LLDBTestResult instantiated more than once") 1272 super(LLDBTestResult, self).__init__(*args) 1273 LLDBTestResult.__singleton__ = self 1274 # Now put this singleton into the lldb module namespace. 1275 lldb.test_result = self 1276 # Computes the format string for displaying the counter. 1277 global suite 1278 counterWidth = len(str(suite.countTestCases())) 1279 self.fmt = "%" + str(counterWidth) + "d: " 1280 self.indentation = ' ' * (counterWidth + 2) 1281 # This counts from 1 .. suite.countTestCases(). 1282 self.counter = 0 1283 1284 def _exc_info_to_string(self, err, test): 1285 """Overrides superclass TestResult's method in order to append 1286 our test config info string to the exception info string.""" 1287 modified_exc_string = '%sConfig=%s-%s' % (super(LLDBTestResult, self)._exc_info_to_string(err, test), 1288 test.getArchitecture(), 1289 test.getCompiler()) 1290 return modified_exc_string 1291 1292 def getDescription(self, test): 1293 doc_first_line = test.shortDescription() 1294 if self.descriptions and doc_first_line: 1295 return '\n'.join((str(test), self.indentation + doc_first_line)) 1296 else: 1297 return str(test) 1298 1299 def startTest(self, test): 1300 self.counter += 1 1301 if self.showAll: 1302 self.stream.write(self.fmt % self.counter) 1303 super(LLDBTestResult, self).startTest(test) 1304 1305 def addError(self, test, err): 1306 global sdir_has_content 1307 sdir_has_content = True 1308 super(LLDBTestResult, self).addError(test, err) 1309 method = getattr(test, "markError", None) 1310 if method: 1311 method() 1312 1313 def addFailure(self, test, err): 1314 global sdir_has_content 1315 sdir_has_content = True 1316 super(LLDBTestResult, self).addFailure(test, err) 1317 method = getattr(test, "markFailure", None) 1318 if method: 1319 method() 1320 1321 def addExpectedFailure(self, test, err): 1322 global sdir_has_content 1323 sdir_has_content = True 1324 super(LLDBTestResult, self).addExpectedFailure(test, err) 1325 method = getattr(test, "markExpectedFailure", None) 1326 if method: 1327 method() 1328 1329 def addSkip(self, test, reason): 1330 global sdir_has_content 1331 sdir_has_content = True 1332 super(LLDBTestResult, self).addSkip(test, reason) 1333 method = getattr(test, "markSkippedTest", None) 1334 if method: 1335 method() 1336 1337 def addUnexpectedSuccess(self, test): 1338 global sdir_has_content 1339 sdir_has_content = True 1340 super(LLDBTestResult, self).addUnexpectedSuccess(test) 1341 method = getattr(test, "markUnexpectedSuccess", None) 1342 if method: 1343 method() 1344 1345 # Invoke the test runner. 1346 if count == 1: 1347 result = unittest2.TextTestRunner(stream=sys.stderr, 1348 verbosity=(1 if progress_bar else verbose), 1349 failfast=failfast, 1350 resultclass=LLDBTestResult).run(suite) 1351 else: 1352 # We are invoking the same test suite more than once. In this case, 1353 # mark __ignore_singleton__ flag as True so the signleton pattern is 1354 # not enforced. 1355 LLDBTestResult.__ignore_singleton__ = True 1356 for i in range(count): 1357 result = unittest2.TextTestRunner(stream=sys.stderr, 1358 verbosity=(1 if progress_bar else verbose), 1359 failfast=failfast, 1360 resultclass=LLDBTestResult).run(suite) 1361 1362 1363if sdir_has_content: 1364 sys.stderr.write("Session logs for test failures/errors/unexpected successes" 1365 " can be found in directory '%s'\n" % sdir_name) 1366 1367fname = os.path.join(sdir_name, "TestFinished") 1368with open(fname, "w") as f: 1369 print >> f, "Test finished at: %s\n" % datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S") 1370 1371# Terminate the test suite if ${LLDB_TESTSUITE_FORCE_FINISH} is defined. 1372# This should not be necessary now. 1373if ("LLDB_TESTSUITE_FORCE_FINISH" in os.environ): 1374 print "Terminating Test suite..." 1375 subprocess.Popen(["/bin/sh", "-c", "kill %s; exit 0" % (os.getpid())]) 1376 1377# Exiting. 1378sys.exit(not result.wasSuccessful) 1379