Merge branch 'master' of http://darcs.haskell.org/testsuite
[ghc.git] / testsuite / driver / runtests.py
1 #
2 # (c) Simon Marlow 2002
3 #
4
5 import sys
6 import os
7 import string
8 import getopt
9 import platform
10 import time
11 import re
12
13 # We don't actually need subprocess in runtests.py, but:
14 # * We do need it in testlibs.py
15 # * We can't import testlibs.py until after we have imported ctypes
16 # * If we import ctypes before subprocess on cygwin, then sys.exit(0)
17 # says "Aborted" and we fail with exit code 134.
18 # So we import it here first, so that the testsuite doesn't appear to fail.
19 try:
20 import subprocess
21 except:
22 pass
23
24 from testutil import *
25 from testglobals import *
26
27 # Readline sometimes spews out ANSI escapes for some values of TERM,
28 # which result in test failures. Thus set TERM to a nice, simple, safe
29 # value.
30 os.environ['TERM'] = 'vt100'
31
32 global config
33 config = getConfig() # get it from testglobals
34
35 # -----------------------------------------------------------------------------
36 # cmd-line options
37
38 long_options = [
39 "config=", # config file
40 "rootdir=", # root of tree containing tests (default: .)
41 "output-summary=", # file in which to save the (human-readable) summary
42 "only=", # just this test (can be give multiple --only= flags)
43 "way=", # just this way
44 "skipway=", # skip this way
45 "threads=", # threads to run simultaneously
46 "check-files-written", # check files aren't written by multiple tests
47 ]
48
49 opts, args = getopt.getopt(sys.argv[1:], "e:", long_options)
50
51 for opt,arg in opts:
52 if opt == '--config':
53 execfile(arg)
54
55 # -e is a string to execute from the command line. For example:
56 # testframe -e 'config.compiler=ghc-5.04'
57 if opt == '-e':
58 exec arg
59
60 if opt == '--rootdir':
61 config.rootdirs.append(arg)
62
63 if opt == '--output-summary':
64 config.output_summary = arg
65
66 if opt == '--only':
67 config.only.append(arg)
68
69 if opt == '--way':
70 if (arg not in config.run_ways and arg not in config.compile_ways and arg not in config.other_ways):
71 sys.stderr.write("ERROR: requested way \'" +
72 arg + "\' does not exist\n")
73 sys.exit(1)
74 config.cmdline_ways = [arg] + config.cmdline_ways
75 if (arg in config.other_ways):
76 config.run_ways = [arg] + config.run_ways
77 config.compile_ways = [arg] + config.compile_ways
78
79 if opt == '--skipway':
80 if (arg not in config.run_ways and arg not in config.compile_ways and arg not in config.other_ways):
81 sys.stderr.write("ERROR: requested way \'" +
82 arg + "\' does not exist\n")
83 sys.exit(1)
84 config.other_ways = filter(neq(arg), config.other_ways)
85 config.run_ways = filter(neq(arg), config.run_ways)
86 config.compile_ways = filter(neq(arg), config.compile_ways)
87
88 if opt == '--threads':
89 config.threads = int(arg)
90 config.use_threads = 1
91
92 if opt == '--check-files-written':
93 config.check_files_written = True
94
95 if config.use_threads == 1:
96 # Trac #1558 says threads don't work in python 2.4.4, but do
97 # in 2.5.2. Probably >= 2.5 is sufficient, but let's be
98 # conservative here.
99 # Some versions of python have things like '1c1' for some of
100 # these components (see trac #3091), but int() chokes on the
101 # 'c1', so we drop it.
102 (maj, min, pat) = platform.python_version_tuple()
103 # We wrap maj, min, and pat in str() to work around a bug in python
104 # 2.6.1
105 maj = int(re.sub('[^0-9].*', '', str(maj)))
106 min = int(re.sub('[^0-9].*', '', str(min)))
107 pat = int(re.sub('[^0-9].*', '', str(pat)))
108 if (maj, min, pat) < (2, 5, 2):
109 print "Warning: Ignoring request to use threads as python version < 2.5.2"
110 config.use_threads = 0
111 # We also need to disable threads for python 2.7.2, because of
112 # this bug: http://bugs.python.org/issue13817
113 elif (maj, min, pat) == (2, 7, 2):
114 print "Warning: Ignoring request to use threads as python version is 2.7.2"
115 print "See http://bugs.python.org/issue13817 for details."
116 config.use_threads = 0
117 if windows:
118 print "Warning: Ignoring request to use threads as running on Windows"
119 config.use_threads = 0
120
121 config.cygwin = False
122 config.msys = False
123 if windows:
124 h = os.popen('uname -s', 'r')
125 v = h.read()
126 h.close()
127 if v.startswith("CYGWIN"):
128 config.cygwin = True
129 elif v.startswith("MINGW32"):
130 config.msys = True
131 else:
132 raise Exception("Can't detect Windows terminal type")
133
134 # Try to use UTF8
135 if windows:
136 import ctypes
137 if config.cygwin:
138 # Is this actually right? Which calling convention does it use?
139 # As of the time of writing, ctypes.windll doesn't exist in the
140 # cygwin python, anyway.
141 mydll = ctypes.cdll
142 else:
143 mydll = ctypes.windll
144
145 # This actually leaves the terminal in codepage 65001 (UTF8) even
146 # after python terminates. We ought really remember the old codepage
147 # and set it back.
148 if mydll.kernel32.SetConsoleCP(65001) == 0:
149 raise Exception("Failure calling SetConsoleCP(65001)")
150 if mydll.kernel32.SetConsoleOutputCP(65001) == 0:
151 raise Exception("Failure calling SetConsoleOutputCP(65001)")
152 else:
153 # Try and find a utf8 locale to use
154 # First see if we already have a UTF8 locale
155 h = os.popen('locale | grep LC_CTYPE | grep -i utf', 'r')
156 v = h.read()
157 h.close()
158 if v == '':
159 # We don't, so now see if 'locale -a' works
160 h = os.popen('locale -a', 'r')
161 v = h.read()
162 h.close()
163 if v != '':
164 # If it does then use the first utf8 locale that is available
165 h = os.popen('locale -a | grep -i "utf8\|utf-8" 2>/dev/null', 'r')
166 v = h.readline().strip()
167 h.close()
168 if v != '':
169 os.environ['LC_ALL'] = v
170 print "setting LC_ALL to", v
171 else:
172 print 'WARNING: No UTF8 locale found.'
173 print 'You may get some spurious test failures.'
174
175 # This has to come after arg parsing as the args can change the compiler
176 get_compiler_info()
177
178 # Can't import this earlier as we need to know if threading will be
179 # enabled or not
180 from testlib import *
181
182 # On Windows we need to set $PATH to include the paths to all the DLLs
183 # in order for the dynamic library tests to work.
184 if windows or darwin:
185 pkginfo = getStdout([config.ghc_pkg, 'dump'])
186 topdir = config.libdir
187 for line in pkginfo.split('\n'):
188 if line.startswith('library-dirs:'):
189 path = line.rstrip()
190 path = re.sub('^library-dirs: ', '', path)
191 path = re.sub('\\$topdir', topdir, path)
192 if path.startswith('"'):
193 path = re.sub('^"(.*)"$', '\\1', path)
194 path = re.sub('\\\\(.)', '\\1', path)
195 if windows:
196 if config.cygwin:
197 # On cygwin we can't put "c:\foo" in $PATH, as : is a
198 # field separator. So convert to /cygdrive/c/foo instead.
199 # Other pythons use ; as the separator, so no problem.
200 path = re.sub('([a-zA-Z]):', '/cygdrive/\\1', path)
201 path = re.sub('\\\\', '/', path)
202 os.environ['PATH'] = os.pathsep.join([path, os.environ.get("PATH", "")])
203 else:
204 # darwin
205 os.environ['DYLD_LIBRARY_PATH'] = os.pathsep.join([path, os.environ.get("DYLD_LIBRARY_PATH", "")])
206
207 global testopts_local
208 testopts_local.x = TestOptions()
209
210 global thisdir_testopts
211 thisdir_testopts = getThisDirTestOpts()
212
213 if config.use_threads:
214 t.lock = threading.Lock()
215 t.thread_pool = threading.Condition(t.lock)
216 t.lockFilesWritten = threading.Lock()
217 t.running_threads = 0
218
219 # if timeout == -1 then we try to calculate a sensible value
220 if config.timeout == -1:
221 config.timeout = int(read_no_crs(config.top + '/timeout/calibrate.out'))
222
223 print 'Timeout is ' + str(config.timeout)
224
225 # -----------------------------------------------------------------------------
226 # The main dude
227
228 if config.rootdirs == []:
229 config.rootdirs = ['.']
230
231 t_files = findTFiles(config.rootdirs)
232
233 print 'Found', len(t_files), '.T files...'
234
235 t = getTestRun()
236
237 # Avoid cmd.exe built-in 'date' command on Windows
238 if not windows:
239 t.start_time = chop(os.popen('date').read())
240 else:
241 t.start_time = 'now'
242
243 print 'Beginning test run at', t.start_time
244
245 # set stdout to unbuffered (is this the best way to do it?)
246 sys.stdout.flush()
247 sys.stdout = os.fdopen(sys.__stdout__.fileno(), "w", 0)
248
249 # First collect all the tests to be run
250 for file in t_files:
251 print '====> Scanning', file
252 newTestDir(os.path.dirname(file))
253 try:
254 execfile(file)
255 except:
256 print '*** framework failure: found an error while executing ', file, ':'
257 t.n_framework_failures = t.n_framework_failures + 1
258 traceback.print_exc()
259
260 # Now run all the tests
261 if config.use_threads:
262 t.running_threads=0
263 for oneTest in parallelTests:
264 oneTest()
265 if config.use_threads:
266 t.thread_pool.acquire()
267 while t.running_threads>0:
268 t.thread_pool.wait()
269 t.thread_pool.release()
270 config.use_threads = False
271 for oneTest in aloneTests:
272 oneTest()
273
274 summary(t, sys.stdout)
275
276 if config.output_summary != '':
277 summary(t, open(config.output_summary, 'w'))
278
279 sys.exit(0)
280