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