runtests.py 8.06 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
# 
# (c) Simon Marlow 2002
#

# ToDo:
#   GHCi tests
#   expect failure for some ways only

import sys
import os
import string
import getopt
13
import platform
14
import time
15
import re
16
import ctypes
17

18 19
from testutil import *
from testglobals import *
20

21 22 23 24 25
# 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'

26 27 28 29 30
if sys.platform == "cygwin":
    cygwin = True
else:
    cygwin = False

31
global config
32
config = getConfig() # get it from testglobals
33 34 35 36 37 38 39 40 41

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

long_options = [
  "config=",  		# config file
  "rootdir=", 		# root of tree containing tests (default: .)
  "output-summary=", 	# file in which to save the (human-readable) summary
  "only=",		# just this test (can be give multiple --only= flags)
42
  "way=",		# just this way
43
  "skipway=",		# skip this way
ei@vuokko.info's avatar
ei@vuokko.info committed
44
  "threads=",           # threads to run simultaneously
45 46 47 48 49 50 51 52 53 54 55 56 57 58
  ]

opts, args = getopt.getopt(sys.argv[1:], "e:", long_options)
       
for opt,arg in opts:
    if opt == '--config':
        execfile(arg)

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

    if opt == '--rootdir':
59
        config.rootdirs.append(arg)
60 61 62 63 64 65 66

    if opt == '--output-summary':
        config.output_summary = arg

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

67
    if opt == '--way':
krc's avatar
krc committed
68
        if (arg not in config.run_ways and arg not in config.compile_ways and arg not in config.other_ways):
69 70 71
            sys.stderr.write("ERROR: requested way \'" +
                             arg + "\' does not exist\n")
            sys.exit(1)
72 73 74 75
        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
76

77 78 79 80 81 82 83 84 85
    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)
        config.other_ways = filter(neq(arg), config.other_ways)
        config.run_ways = filter(neq(arg), config.run_ways)
        config.compile_ways = filter(neq(arg), config.compile_ways)

ei@vuokko.info's avatar
ei@vuokko.info committed
86
    if opt == '--threads':
Ian Lynagh's avatar
Ian Lynagh committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
        config.threads = int(arg)
        config.use_threads = 1

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)))
    if (maj, min, pat) < (2, 5, 2):
        print "Warning: Ignoring request to use threads as python version < 2.5.2"
        config.use_threads = 0
    if windows:
        print "Warning: Ignoring request to use threads as running on Windows"
        config.use_threads = 0
109

110 111
# Try to use UTF8
if windows:
112
    if cygwin:
Ian Lynagh's avatar
Ian Lynagh committed
113 114 115 116 117 118 119
        # Is this actually right? Which calling convention does it use?
        # As of the time of writing, ctypes.windll doesn't exist in the
        # cygwin python, anyway.
        mydll = ctypes.cdll
    else:
        mydll = ctypes.windll

120 121 122
    # 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
123
    if mydll.kernel32.SetConsoleCP(65001) == 0:
124
        raise Exception("Failure calling SetConsoleCP(65001)")
Ian Lynagh's avatar
Ian Lynagh committed
125
    if mydll.kernel32.SetConsoleOutputCP(65001) == 0:
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
        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
                print "setting LC_ALL to", v
            else:
                print 'WARNING: No UTF8 locale found.'
                print 'You may get some spurious test failures.'

150 151 152
# This has to come after arg parsing as the args can change the compiler
get_compiler_info()

153 154 155 156
# Can't import this earlier as we need to know if threading will be
# enabled or not
from testlib import *

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
# On Windows we need to set $PATH to include the paths to all the DLLs
# in order for the dynamic library tests to work.
if windows:
    if have_subprocess:
        libs = getStdout([config.ghc_pkg, 'list', '--simple-output'])
        for lib in libs.split(' '):
            path = getStdout([config.ghc_pkg, 'field', lib, 'library-dirs'])
            # We assume there is only 1 path, and make some assumptions
            # about what it looks like. Unquoted strings we leave alone,
            # and we assume that a \ escapes the following char if it's
            # quoted. The common case here is "c:\\foo bar\\baz" where
            # we want to undouble the backslashes.
            path = path.rstrip();
            path = re.sub('^library-dirs: ', '', path)
            if path.startswith('"'):
                path = re.sub('^"(.*)"$', '\\1', path)
                path = re.sub('\\\\(.)', '\\1', path)
            if 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:
        raise Exception("Need subprocess on Windows, but don't have it")

184 185 186 187 188 189 190 191 192 193 194
global testopts_local
testopts_local.x = TestOptions()

global thisdir_testopts
thisdir_testopts = getThisDirTestOpts()

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

195 196 197 198 199 200
# 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'))

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

201 202 203
# -----------------------------------------------------------------------------
# The main dude

204 205 206 207
if config.rootdirs == []:
    config.rootdirs = ['.']

t_files = findTFiles(config.rootdirs)
208 209 210 211 212 213 214 215 216 217 218 219

print 'Found', len(t_files), '.T files...'

t = getTestRun()

t.start_time = chop(os.popen('date').read())
print 'Beginning test run at', t.start_time

# set stdout to unbuffered (is this the best way to do it?)
sys.stdout.flush()
sys.stdout = os.fdopen(sys.__stdout__.fileno(), "w", 0)

220
# First collect all the tests to be run
221
for file in t_files:
222
    print '====> Scanning', file
223 224 225 226
    newTestDir(os.path.dirname(file))
    try:
        execfile(file)
    except:
227
        print '*** framework failure: found an error while executing ', file, ':'
228
        t.n_framework_failures = t.n_framework_failures + 1
229
        traceback.print_exc()
230 231 232 233 234 235 236 237 238 239 240

# Now run all the tests
if config.use_threads:
    t.running_threads=0
for oneTest in allTests:
    oneTest()
if config.use_threads:
    t.thread_pool.acquire()
    while t.running_threads>0:
        t.thread_pool.wait()
    t.thread_pool.release()
ei@vuokko.info's avatar
ei@vuokko.info committed
241
        
242 243 244 245 246 247 248
summary(t, sys.stdout)

if config.output_summary != '':
    summary(t, open(config.output_summary, 'w'))

sys.exit(0)