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