runtests.py 10.9 KB
Newer Older
1 2 3 4
# 
# (c) Simon Marlow 2002
#

5 6
from __future__ import print_function

7 8 9 10
import sys
import os
import string
import getopt
11
import platform
12
import time
13
import re
14

15 16 17 18 19 20
# We don't actually need subprocess in runtests.py, but:
# * We do need it in testlibs.py
# * We can't import testlibs.py until after we have imported ctypes
# * If we import ctypes before subprocess on cygwin, then sys.exit(0)
#   says "Aborted" and we fail with exit code 134.
# So we import it here first, so that the testsuite doesn't appear to fail.
21
import subprocess
22

23 24 25 26 27
PYTHON3 = sys.version_info >= (3, 0)
if PYTHON3:
    print("*** WARNING: running testsuite using Python 3.\n"
          "*** Python 3 support is experimental. See Trac #9184.")

28 29
from testutil import *
from testglobals import *
30

31 32 33 34 35
# Readline sometimes spews out ANSI escapes for some values of TERM,
# which result in test failures. Thus set TERM to a nice, simple, safe
# value.
os.environ['TERM'] = 'vt100'

36
global config
37
config = getConfig() # get it from testglobals
38 39 40 41 42

# -----------------------------------------------------------------------------
# cmd-line options

long_options = [
43 44
  "configfile=",	# config file
  "config=",  		# config field
45
  "rootdir=", 		# root of tree containing tests (default: .)
thomie's avatar
thomie committed
46 47
  "summary-file=",      # file in which to save the (human-readable) summary
  "no-print-summary=",  # should we print the summary?
48
  "only=",		# just this test (can be give multiple --only= flags)
49
  "way=",		# just this way
50
  "skipway=",		# skip this way
ei@vuokko.info's avatar
ei@vuokko.info committed
51
  "threads=",           # threads to run simultaneously
52
  "check-files-written", # check files aren't written by multiple tests
53
  "verbose=",          # verbose (0,1,2 so far)
54
  "skip-perf-tests",       # skip performance tests
55 56 57 58 59
  ]

opts, args = getopt.getopt(sys.argv[1:], "e:", long_options)
       
for opt,arg in opts:
60
    if opt == '--configfile':
61
        exec(open(arg).read())
62 63 64 65

    # -e is a string to execute from the command line.  For example:
    # testframe -e 'config.compiler=ghc-5.04'
    if opt == '-e':
66
        exec(arg)
67

68 69 70 71
    if opt == '--config':
        field, value = arg.split('=', 1)
        setattr(config, field, value)

72
    if opt == '--rootdir':
73
        config.rootdirs.append(arg)
74

thomie's avatar
thomie committed
75 76 77 78 79
    if opt == '--summary-file':
        config.summary_file = arg

    if opt == '--no-print-summary':
        config.no_print_summary = True
80 81 82 83

    if opt == '--only':
        config.only.append(arg)

84
    if opt == '--way':
krc's avatar
krc committed
85
        if (arg not in config.run_ways and arg not in config.compile_ways and arg not in config.other_ways):
86 87 88
            sys.stderr.write("ERROR: requested way \'" +
                             arg + "\' does not exist\n")
            sys.exit(1)
89 90 91 92
        config.cmdline_ways = [arg] + config.cmdline_ways
        if (arg in config.other_ways):
            config.run_ways = [arg] + config.run_ways
            config.compile_ways = [arg] + config.compile_ways
ei@vuokko.info's avatar
ei@vuokko.info committed
93

94 95 96 97 98
    if opt == '--skipway':
        if (arg not in config.run_ways and arg not in config.compile_ways and arg not in config.other_ways):
            sys.stderr.write("ERROR: requested way \'" +
                             arg + "\' does not exist\n")
            sys.exit(1)
99 100 101
        config.other_ways = [w for w in config.other_ways if w != arg]
        config.run_ways = [w for w in config.run_ways if w != arg]
        config.compile_ways = [w for w in config.compile_ways if w != arg]
102

ei@vuokko.info's avatar
ei@vuokko.info committed
103
    if opt == '--threads':
Ian Lynagh's avatar
Ian Lynagh committed
104 105 106
        config.threads = int(arg)
        config.use_threads = 1

107 108 109
    if opt == '--check-files-written':
        config.check_files_written = True

110 111 112
    if opt == '--skip-perf-tests':
        config.skip_perf_tests = True

113
    if opt == '--verbose':
114 115
        if arg not in ["0","1","2","3","4"]:
            sys.stderr.write("ERROR: requested verbosity %s not supported, use 0,1,2,3 or 4" % arg)
116 117 118 119
            sys.exit(1)
        config.verbose = int(arg)


Ian Lynagh's avatar
Ian Lynagh committed
120 121 122 123 124 125 126 127 128 129 130 131 132
if config.use_threads == 1:
    # Trac #1558 says threads don't work in python 2.4.4, but do
    # in 2.5.2. Probably >= 2.5 is sufficient, but let's be
    # conservative here.
    # Some versions of python have things like '1c1' for some of
    # these components (see trac #3091), but int() chokes on the
    # 'c1', so we drop it.
    (maj, min, pat) = platform.python_version_tuple()
    # We wrap maj, min, and pat in str() to work around a bug in python
    # 2.6.1
    maj = int(re.sub('[^0-9].*', '', str(maj)))
    min = int(re.sub('[^0-9].*', '', str(min)))
    pat = int(re.sub('[^0-9].*', '', str(pat)))
133 134 135
    if (maj, min) < (2, 6):
        print("Python < 2.6 is not supported")
        sys.exit(1)
136 137 138
    # We also need to disable threads for python 2.7.2, because of
    # this bug: http://bugs.python.org/issue13817
    elif (maj, min, pat) == (2, 7, 2):
139 140
        print("Warning: Ignoring request to use threads as python version is 2.7.2")
        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")
Ian Lynagh's avatar
Ian Lynagh committed
144
        config.use_threads = 0
145

Ian Lynagh's avatar
Ian Lynagh committed
146 147
config.cygwin = False
config.msys = False
148

Ian Lynagh's avatar
Ian Lynagh committed
149
if windows:
150 151 152 153
    h = os.popen('uname -s', 'r')
    v = h.read()
    h.close()
    if v.startswith("CYGWIN"):
Ian Lynagh's avatar
Ian Lynagh committed
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"
Ian Lynagh's avatar
Ian Lynagh committed
158
        config.msys = True
159
    else:
160
        raise Exception("Can't detect Windows terminal type")
Ian Lynagh's avatar
Ian Lynagh committed
161

162 163
# Try to use UTF8
if windows:
164
    import ctypes
165 166
    # Windows Python provides windll, mingw python provides cdll.
    if hasattr(ctypes, 'windll'):
Ian Lynagh's avatar
Ian Lynagh committed
167
        mydll = ctypes.windll
168 169
    else:
        mydll = ctypes.cdll
Ian Lynagh's avatar
Ian Lynagh committed
170

171 172 173
    # This actually leaves the terminal in codepage 65001 (UTF8) even
    # after python terminates. We ought really remember the old codepage
    # and set it back.
Ian Lynagh's avatar
Ian Lynagh committed
174
    if mydll.kernel32.SetConsoleCP(65001) == 0:
175
        raise Exception("Failure calling SetConsoleCP(65001)")
Ian Lynagh's avatar
Ian Lynagh committed
176
    if mydll.kernel32.SetConsoleOutputCP(65001) == 0:
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
        raise Exception("Failure calling SetConsoleOutputCP(65001)")
else:
    # Try and find a utf8 locale to use
    # First see if we already have a UTF8 locale
    h = os.popen('locale | grep LC_CTYPE | grep -i utf', 'r')
    v = h.read()
    h.close()
    if v == '':
        # We don't, so now see if 'locale -a' works
        h = os.popen('locale -a', 'r')
        v = h.read()
        h.close()
        if v != '':
            # If it does then use the first utf8 locale that is available
            h = os.popen('locale -a | grep -i "utf8\|utf-8" 2>/dev/null', 'r')
            v = h.readline().strip()
            h.close()
            if v != '':
                os.environ['LC_ALL'] = v
196
                print("setting LC_ALL to", v)
197
            else:
198 199
                print('WARNING: No UTF8 locale found.')
                print('You may get some spurious test failures.')
200

201 202 203
# This has to come after arg parsing as the args can change the compiler
get_compiler_info()

204 205 206 207
# Can't import this earlier as we need to know if threading will be
# enabled or not
from testlib import *

208 209
# On Windows we need to set $PATH to include the paths to all the DLLs
# in order for the dynamic library tests to work.
210 211 212
if windows or darwin:
    pkginfo = getStdout([config.ghc_pkg, 'dump'])
    topdir = config.libdir
213 214 215
    if windows:
        mingw = os.path.join(topdir, '../mingw/bin')
        os.environ['PATH'] = os.pathsep.join([os.environ.get("PATH", ""), mingw])
216 217 218 219
    for line in pkginfo.split('\n'):
        if line.startswith('library-dirs:'):
            path = line.rstrip()
            path = re.sub('^library-dirs: ', '', path)
220 221 222 223
            # Use string.replace instead of re.sub, because re.sub
            # interprets backslashes in the replacement string as
            # escape sequences.
            path = path.replace('$topdir', topdir)
224 225 226 227 228 229 230 231 232 233 234 235 236 237
            if path.startswith('"'):
                path = re.sub('^"(.*)"$', '\\1', path)
                path = re.sub('\\\\(.)', '\\1', path)
            if windows:
                if config.cygwin:
                    # On cygwin we can't put "c:\foo" in $PATH, as : is a
                    # field separator. So convert to /cygdrive/c/foo instead.
                    # Other pythons use ; as the separator, so no problem.
                    path = re.sub('([a-zA-Z]):', '/cygdrive/\\1', path)
                    path = re.sub('\\\\', '/', path)
                os.environ['PATH'] = os.pathsep.join([path, os.environ.get("PATH", "")])
            else:
                # darwin
                os.environ['DYLD_LIBRARY_PATH'] = os.pathsep.join([path, os.environ.get("DYLD_LIBRARY_PATH", "")])
238

239 240 241 242 243 244
global testopts_local
testopts_local.x = TestOptions()

if config.use_threads:
    t.lock = threading.Lock()
    t.thread_pool = threading.Condition(t.lock)
245
    t.lockFilesWritten = threading.Lock()
246 247
    t.running_threads = 0

248 249 250 251
# if timeout == -1 then we try to calculate a sensible value
if config.timeout == -1:
    config.timeout = int(read_no_crs(config.top + '/timeout/calibrate.out'))

252
print('Timeout is ' + str(config.timeout))
253

254 255 256
# -----------------------------------------------------------------------------
# The main dude

257 258 259 260
if config.rootdirs == []:
    config.rootdirs = ['.']

t_files = findTFiles(config.rootdirs)
261

262
print('Found', len(t_files), '.T files...')
263 264 265

t = getTestRun()

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 273 274 275 276 277
if PYTHON3:
    # in Python 3, we output text, which cannot be unbuffered
    sys.stdout = os.fdopen(sys.__stdout__.fileno(), "w")
else:
    # set stdout to unbuffered (is this the best way to do it?)
    sys.stdout = os.fdopen(sys.__stdout__.fileno(), "w", 0)
278

279
# First collect all the tests to be run
280
for file in t_files:
281
    if_verbose(2, '====> Scanning %s' % file)
282 283
    newTestDir(os.path.dirname(file))
    try:
284 285 286
        exec(open(file).read())
    except Exception:
        print('*** framework failure: found an error while executing ', file, ':')
287
        t.n_framework_failures = t.n_framework_failures + 1
288
        traceback.print_exc()
289

ian@well-typed.com's avatar
ian@well-typed.com committed
290 291
if config.list_broken:
    global brokens
292 293 294 295
    print('')
    print('Broken tests:')
    print(' '.join(map (lambda bdn: '#' + str(bdn[0]) + '(' + bdn[1] + '/' + bdn[2] + ')', brokens)))
    print('')
296 297

    if t.n_framework_failures != 0:
298 299
        print('WARNING:', str(t.n_framework_failures), 'framework failures!')
        print('')
ian@well-typed.com's avatar
ian@well-typed.com committed
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
else:
    # Now run all the tests
    if config.use_threads:
        t.running_threads=0
    for oneTest in parallelTests:
        if stopping():
            break
        oneTest()
    if config.use_threads:
        t.thread_pool.acquire()
        while t.running_threads>0:
            t.thread_pool.wait()
        t.thread_pool.release()
    config.use_threads = False
    for oneTest in aloneTests:
        if stopping():
            break
        oneTest()
ei@vuokko.info's avatar
ei@vuokko.info committed
318
        
thomie's avatar
thomie committed
319
    summary(t, sys.stdout, config.no_print_summary)
320

thomie's avatar
thomie committed
321 322
    if config.summary_file != '':
        summary(t, open(config.summary_file, 'w'))
323 324 325

sys.exit(0)