21f5172dc3472212f97724269365b870966dc390
[scons.git] / runtest.py
1 #!/usr/bin/env python
2 #
3 # runtest.py - wrapper script for running SCons tests
4 #
5 # This script mainly exists to set PYTHONPATH to the right list of
6 # directories to test the SCons modules.
7 #
8 # By default, it directly uses the modules in the local tree:
9 # ./src/ (source files we ship) and ./etc/ (other modules we don't)
10 #
11 # When "-b aegis" is specified, it assumes it's in a directory
12 # in which an Aegis build (aeb) has been performed, and sets
13 # PYTHONPATH so that it *only* references the modules that have
14 # unpacked from the built packages, to test whether the packages
15 # are good.
16 #
17 # Options:
18 #
19 #       -a              Run all tests; does a virtual 'find' for
20 #                       all SCons tests under the current directory.
21 #
22 #       -d              Debug.  Runs the script under the Python
23 #                       debugger (pdb.py) so you don't have to
24 #                       muck with PYTHONPATH yourself.
25 #
26 #       -p package      Test against the specified package.
27 #
28 #       -q              Quiet.  By default, runtest.py prints the
29 #                       command line it will execute before
30 #                       executing it.  This suppresses that print.
31 #
32 #       -X              The scons "script" is an executable; don't
33 #                       feed it to Python.
34 #
35 #       -x scons        The scons script to use for tests.
36 #
37 # (Note:  There used to be a -v option that specified the SCons
38 # version to be tested, when we were installing in a version-specific
39 # library directory.  If we ever resurrect that as the default, then
40 # you can find the appropriate code in the 0.04 version of this script,
41 # rather than reinventing that wheel.)
42 #
43
44 import getopt
45 import os
46 import os.path
47 import re
48 import string
49 import sys
50
51 all = 0
52 debug = ''
53 tests = []
54 printcmd = 1
55 package = None
56 scons = None
57 scons_exec = None
58
59 if sys.platform == 'win32':
60     lib_dir = os.path.join(sys.exec_prefix, "lib")
61 else:
62     lib_dir = os.path.join(sys.exec_prefix, "lib", "python" + sys.version[0:3])
63
64 opts, tests = getopt.getopt(sys.argv[1:], "adqp:Xx:",
65                             ['all', 'debug', 'exec=', 'quiet', 'package='])
66
67 for o, a in opts:
68     if o == '-a' or o == '--all': all = 1
69     elif o == '-d' or o == '--debug': debug = os.path.join(lib_dir, "pdb.py")
70     elif o == '-q' or o == '--quiet': printcmd = 0
71     elif o == '-p' or o == '--package': package = a
72     elif o == '-X': scons_exec = 1
73     elif o == '-x' or o == '--exec': scons = a
74
75 cwd = os.getcwd()
76
77 if tests:
78     map(os.path.abspath, tests)
79 elif all:
80     def find_Test_py(arg, dirname, names):
81         global tests
82         n = filter(lambda n: n[-8:] == "Tests.py", names)
83         tests.extend(map(lambda x,d=dirname: os.path.join(d, x), n))
84     os.path.walk('src', find_Test_py, 0)
85
86     def find_py(arg, dirname, names):
87         global tests
88         n = filter(lambda n: n[-3:] == ".py", names)
89         tests.extend(map(lambda x,d=dirname: os.path.join(d, x), n))
90     os.path.walk('test', find_py, 0)
91
92     tests.sort()
93
94 if package:
95
96     dir = {
97         'deb'        : 'usr',
98         'rpm'        : 'usr',
99         'src-tar-gz' : '',
100         'src-zip'    : '',
101         'tar-gz'     : '',
102         'zip'        : '',
103     }
104
105     lib = {
106         'deb'        : os.path.join('python2.1', 'site-packages')
107     }
108
109     if not dir.has_key(package):
110         sys.stderr.write("Unknown package '%s'\n" % package)
111         sys.exit(2)
112
113     test_dir = os.path.join(cwd, 'build', 'test-%s' % package)
114
115     if sys.platform == 'win32':
116         scons_dir = os.path.join(test_dir, dir[package], 'Scripts')
117         lib_dir = os.path.join(test_dir, dir[package])
118     else:
119         scons_dir = os.path.join(test_dir, dir[package], 'bin')
120         l = lib.get(package, 'scons')
121         lib_dir = os.path.join(test_dir, dir[package], 'lib', l)
122
123 else:
124
125     scons_dir = os.path.join(cwd, 'src', 'script')
126
127     lib_dir = os.path.join(cwd, 'src', 'engine')
128
129 if scons:
130     # Let the version of SCons that the -x option pointed to find
131     # its own modules.
132     os.environ['SCONS'] = scons
133 else:
134     # Because SCons is really aggressive about finding its modules,
135     # it sometimes finds SCons modules elsewhere on the system.
136     # This forces SCons to use the modules that are being tested.
137     os.environ['SCONS_LIB_DIR'] = lib_dir
138
139 if scons_exec:
140     os.environ['SCONS_EXEC'] = '1'
141
142 os.environ['PYTHONPATH'] = lib_dir + \
143                            os.pathsep + \
144                            os.path.join(cwd, 'build', 'etc') + \
145                            os.pathsep + \
146                            os.path.join(cwd, 'etc')
147
148 os.chdir(scons_dir)
149
150 fail = []
151 no_result = []
152
153 for path in tests:
154     if os.path.isabs(path):
155         abs = path
156     else:
157         abs = os.path.join(cwd, path)
158     cmd = string.join(["python", debug, abs], " ")
159     if printcmd:
160         print cmd
161     s = os.system(cmd)
162     if s == 1 or s == 256:
163         fail.append(path)
164     elif s == 2 or s == 512:
165         no_result.append(path)
166     elif s != 0:
167         print "Unexpected exit status %d" % s
168
169 if len(tests) != 1:
170     if fail:
171         if len(fail) == 1:
172             str = "test"
173         else:
174             str = "%d tests" % len(fail)
175         print "\nFailed the following %s:" % str
176         print "\t", string.join(fail, "\n\t")
177     if no_result:
178         if len(no_result) == 1:
179             str = "test"
180         else:
181             str = "%d tests" % len(no_result)
182         print "\nNO RESULT from the following %s:" % str
183         print "\t", string.join(no_result, "\n\t")
184
185 sys.exit(len(fail) + len(no_result))