summaryrefslogtreecommitdiff
path: root/testsuite/driver
diff options
context:
space:
mode:
Diffstat (limited to 'testsuite/driver')
-rw-r--r--testsuite/driver/junit.py38
-rw-r--r--testsuite/driver/runtests.py240
-rw-r--r--testsuite/driver/testglobals.py47
-rw-r--r--testsuite/driver/testlib.py150
-rw-r--r--testsuite/driver/testutil.py19
5 files changed, 277 insertions, 217 deletions
diff --git a/testsuite/driver/junit.py b/testsuite/driver/junit.py
new file mode 100644
index 0000000000..f2dbebb96a
--- /dev/null
+++ b/testsuite/driver/junit.py
@@ -0,0 +1,38 @@
+from datetime import datetime
+import xml.etree.ElementTree as ET
+
+def junit(t):
+ testsuites = ET.Element('testsuites')
+ testsuite = ET.SubElement(testsuites, 'testsuite',
+ id = "0",
+ package = 'ghc',
+ tests = str(t.total_tests),
+ failures = str(len(t.unexpected_failures) + len(t.unexpected_stat_failures)),
+ errors = str(len(t.framework_failures)),
+ timestamp = datetime.now().isoformat())
+
+ for res_type, group in [('stat failure', t.unexpected_stat_failures),
+ ('unexpected failure', t.unexpected_failures)]:
+ for (directory, testname, reason, way) in group:
+ testcase = ET.SubElement(testsuite, 'testcase',
+ classname = testname,
+ name = way)
+ result = ET.SubElement(testcase, 'failure',
+ type = res_type,
+ message = reason)
+
+ for (directory, testname, reason, way) in t.framework_failures:
+ testcase = ET.SubElement(testsuite, 'testcase',
+ classname = testname,
+ name = way)
+ result = ET.SubElement(testcase, 'error',
+ type = "framework failure",
+ message = reason)
+
+ for (directory, testname, way) in t.expected_passes:
+ testcase = ET.SubElement(testsuite, 'testcase',
+ classname = testname,
+ name = way)
+
+ return ET.ElementTree(testsuites)
+
diff --git a/testsuite/driver/runtests.py b/testsuite/driver/runtests.py
index 7e4f375a2c..b956239d2a 100644
--- a/testsuite/driver/runtests.py
+++ b/testsuite/driver/runtests.py
@@ -4,17 +4,16 @@
# (c) Simon Marlow 2002
#
-from __future__ import print_function
-
+import argparse
import signal
import sys
import os
-import string
-import getopt
+import io
import shutil
import tempfile
import time
import re
+import traceback
# We don't actually need subprocess in runtests.py, but:
# * We do need it in testlibs.py
@@ -24,13 +23,15 @@ import re
# So we import it here first, so that the testsuite doesn't appear to fail.
import subprocess
-from testutil import *
-from testglobals import *
+from testutil import getStdout, Watcher
+from testglobals import getConfig, ghc_env, getTestRun, TestOptions, brokens
+from junit import junit
# 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'
+ghc_env['TERM'] = 'vt100'
global config
config = getConfig() # get it from testglobals
@@ -41,81 +42,69 @@ def signal_handler(signal, frame):
# -----------------------------------------------------------------------------
# cmd-line options
-long_options = [
- "configfile=", # config file
- "config=", # config field
- "rootdir=", # root of tree containing tests (default: .)
- "summary-file=", # file in which to save the (human-readable) summary
- "no-print-summary=", # should we print the summary?
- "only=", # just this test (can be give multiple --only= flags)
- "way=", # just this way
- "skipway=", # skip this way
- "threads=", # threads to run simultaneously
- "check-files-written", # check files aren't written by multiple tests
- "verbose=", # verbose (0,1,2 so far)
- "skip-perf-tests", # skip performance tests
- ]
-
-opts, args = getopt.getopt(sys.argv[1:], "e:", long_options)
-
-for opt,arg in opts:
- if opt == '--configfile':
- exec(open(arg).read())
-
- # -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 == '--config':
- field, value = arg.split('=', 1)
- setattr(config, field, value)
-
- if opt == '--rootdir':
- config.rootdirs.append(arg)
-
- if opt == '--summary-file':
- config.summary_file = arg
-
- if opt == '--no-print-summary':
- config.no_print_summary = True
-
- if opt == '--only':
- config.run_only_some_tests = True
- config.only.add(arg)
-
- if opt == '--way':
- 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.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
-
- 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 = [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]
-
- if opt == '--threads':
- config.threads = int(arg)
- config.use_threads = 1
-
- if opt == '--skip-perf-tests':
- config.skip_perf_tests = True
-
- if opt == '--verbose':
- if arg not in ["0","1","2","3","4","5"]:
- sys.stderr.write("ERROR: requested verbosity %s not supported, use 0,1,2,3,4 or 5" % arg)
- sys.exit(1)
- config.verbose = int(arg)
-
+parser = argparse.ArgumentParser(description="GHC's testsuite driver")
+
+parser.add_argument("-e", action='append', help="A string to execute from the command line.")
+parser.add_argument("--config-file", action="append", help="config file")
+parser.add_argument("--config", action='append', help="config field")
+parser.add_argument("--rootdir", action='append', help="root of tree containing tests (default: .)")
+parser.add_argument("--summary-file", help="file in which to save the (human-readable) summary")
+parser.add_argument("--no-print-summary", action="store_true", help="should we print the summary?")
+parser.add_argument("--only", action="append", help="just this test (can be give multiple --only= flags)")
+parser.add_argument("--way", action="append", help="just this way")
+parser.add_argument("--skipway", action="append", help="skip this way")
+parser.add_argument("--threads", type=int, help="threads to run simultaneously")
+parser.add_argument("--verbose", type=int, choices=[0,1,2,3,4,5], help="verbose (Values 0 through 5 accepted)")
+parser.add_argument("--skip-perf-tests", action="store_true", help="skip performance tests")
+parser.add_argument("--junit", type=argparse.FileType('wb'), help="output testsuite summary in JUnit format")
+
+args = parser.parse_args()
+
+for e in args.e:
+ exec(e)
+
+for arg in args.config_file:
+ exec(open(arg).read())
+
+for arg in args.config:
+ field, value = arg.split('=', 1)
+ setattr(config, field, value)
+
+all_ways = config.run_ways+config.compile_ways+config.other_ways
+config.rootdirs = args.rootdir
+config.summary_file = args.summary_file
+config.no_print_summary = args.no_print_summary
+
+if args.only:
+ config.only = args.only
+ config.run_only_some_tests = True
+
+if args.way:
+ for way in args.way:
+ if way not in all_ways:
+ print('WARNING: Unknown WAY %s in --way' % way)
+ else:
+ config.cmdline_ways += [way]
+ if way in config.other_ways:
+ config.run_ways += [way]
+ config.compile_ways += [way]
+
+if args.skipway:
+ for way in args.skipway:
+ if way not in all_ways:
+ print('WARNING: Unknown WAY %s in --skipway' % way)
+
+ config.other_ways = [w for w in config.other_ways if w not in args.skipway]
+ config.run_ways = [w for w in config.run_ways if w not in args.skipway]
+ config.compile_ways = [w for w in config.compile_ways if w not in args.skipway]
+
+if args.threads:
+ config.threads = args.threads
+ config.use_threads = True
+
+if args.verbose is not None:
+ config.verbose = args.verbose
+config.skip_perf_tests = args.skip_perf_tests
config.cygwin = False
config.msys = False
@@ -161,7 +150,7 @@ else:
h.close()
if v == '':
# We don't, so now see if 'locale -a' works
- h = os.popen('locale -a', 'r')
+ h = os.popen('locale -a | grep -F .', 'r')
v = h.read()
h.close()
if v != '':
@@ -171,6 +160,7 @@ else:
h.close()
if v != '':
os.environ['LC_ALL'] = v
+ ghc_env['LC_ALL'] = v
print("setting LC_ALL to", v)
else:
print('WARNING: No UTF8 locale found.')
@@ -183,14 +173,30 @@ get_compiler_info()
# enabled or not
from testlib import *
+def format_path(path):
+ if windows:
+ if os.pathsep == ':':
+ # If using msys2 python instead of mingw we have to change the drive
+ # letter representation. Otherwise it thinks we're adding two env
+ # variables E and /Foo when we add E:/Foo.
+ path = re.sub('([a-zA-Z]):', '/\\1', path)
+ 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)
+ return path
+
# 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 or darwin:
- pkginfo = str(getStdout([config.ghc_pkg, 'dump']))
+ pkginfo = getStdout([config.ghc_pkg, 'dump'])
topdir = config.libdir
if windows:
- mingw = os.path.join(topdir, '../mingw/bin')
- os.environ['PATH'] = os.pathsep.join([os.environ.get("PATH", ""), mingw])
+ mingw = os.path.abspath(os.path.join(topdir, '../mingw/bin'))
+ mingw = format_path(mingw)
+ ghc_env['PATH'] = os.pathsep.join([ghc_env.get("PATH", ""), mingw])
for line in pkginfo.split('\n'):
if line.startswith('library-dirs:'):
path = line.rstrip()
@@ -203,18 +209,12 @@ if windows or darwin:
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", "")])
+ path = format_path(path)
+ ghc_env['PATH'] = os.pathsep.join([path, ghc_env.get("PATH", "")])
else:
# darwin
- os.environ['DYLD_LIBRARY_PATH'] = os.pathsep.join([path, os.environ.get("DYLD_LIBRARY_PATH", "")])
+ ghc_env['DYLD_LIBRARY_PATH'] = os.pathsep.join([path, ghc_env.get("DYLD_LIBRARY_PATH", "")])
-global testopts_local
testopts_local.x = TestOptions()
# if timeout == -1 then we try to calculate a sensible value
@@ -286,51 +286,63 @@ for name in config.only:
framework_fail(name, '', 'test not found')
else:
# Let user fix .T file errors before reporting on unfound tests.
- # The reson the test can not be found is likely because of those
+ # The reason the test can not be found is likely because of those
# .T file errors.
pass
if config.list_broken:
- global brokens
print('')
print('Broken tests:')
print(' '.join(map (lambda bdn: '#' + str(bdn[0]) + '(' + bdn[1] + '/' + bdn[2] + ')', brokens)))
print('')
if t.framework_failures:
- print('WARNING:', len(framework_failures), 'framework failures!')
+ print('WARNING:', len(t.framework_failures), 'framework failures!')
print('')
else:
# completion watcher
watcher = Watcher(len(parallelTests))
# Now run all the tests
- for oneTest in parallelTests:
- if stopping():
- break
- oneTest(watcher)
-
- # wait for parallel tests to finish
- if not stopping():
- watcher.wait()
-
- # Run the following tests purely sequential
- config.use_threads = False
- for oneTest in aloneTests:
- if stopping():
- break
- oneTest(watcher)
+ try:
+ for oneTest in parallelTests:
+ if stopping():
+ break
+ oneTest(watcher)
+
+ # wait for parallel tests to finish
+ if not stopping():
+ watcher.wait()
+
+ # Run the following tests purely sequential
+ config.use_threads = False
+ for oneTest in aloneTests:
+ if stopping():
+ break
+ oneTest(watcher)
+ except KeyboardInterrupt:
+ pass
# flush everything before we continue
sys.stdout.flush()
summary(t, sys.stdout, config.no_print_summary)
- if config.summary_file != '':
+ if config.summary_file:
with open(config.summary_file, 'w') as file:
summary(t, file)
-cleanup_and_exit(0)
+ if args.junit:
+ junit(t).write(args.junit)
+
+if len(t.unexpected_failures) > 0 or \
+ len(t.unexpected_stat_failures) > 0 or \
+ len(t.framework_failures) > 0:
+ exitcode = 1
+else:
+ exitcode = 0
+
+cleanup_and_exit(exitcode)
# Note [Running tests in /tmp]
#
diff --git a/testsuite/driver/testglobals.py b/testsuite/driver/testglobals.py
index fc050e6908..311e39be7f 100644
--- a/testsuite/driver/testglobals.py
+++ b/testsuite/driver/testglobals.py
@@ -1,4 +1,4 @@
-#
+#
# (c) Simon Marlow 2002
#
@@ -9,7 +9,7 @@
# variable config below. The fields of the structure are filled in by
# the appropriate config script(s) for this compiler/platform, in
# ../config.
-#
+#
# Bits of the structure may also be filled in from the command line,
# via the build system, using the '-e' option to runtests.
@@ -27,7 +27,9 @@ class TestConfig:
self.only = set()
# Accept new output which differs from the sample?
- self.accept = 0
+ self.accept = False
+ self.accept_platform = False
+ self.accept_os = False
# File in which to save the summary
self.summary_file = ''
@@ -41,9 +43,6 @@ class TestConfig:
# with --verbose=0.
self.no_print_summary = False
- # File in which to save the times
- self.times_file = ''
-
# What platform are we running on?
self.platform = ''
self.os = ''
@@ -70,7 +69,7 @@ class TestConfig:
# Flags we always give to this compiler
self.compiler_always_flags = []
-
+
# Which ways to run tests (when compiling and running respectively)
# Other ways are added from the command line if we have the appropriate
# libraries.
@@ -103,16 +102,22 @@ class TestConfig:
# Do we have SMP support?
self.have_smp = False
+ # Is gdb avaliable?
+ self.have_gdb = False
+
+ # Is readelf available?
+ self.have_readelf = False
+
# Are we testing an in-tree compiler?
self.in_tree_compiler = True
# the timeout program
self.timeout_prog = ''
self.timeout = 300
-
+
# threads
self.threads = 1
- self.use_threads = 0
+ self.use_threads = False
# Should we skip performance tests
self.skip_perf_tests = False
@@ -123,6 +128,12 @@ config = TestConfig()
def getConfig():
return config
+import os
+# Hold our modified GHC testrunning environment so we don't poison the current
+# python's environment.
+global ghc_env
+ghc_env = os.environ.copy()
+
# -----------------------------------------------------------------------------
# Information about the current test run
@@ -140,6 +151,7 @@ class TestRun:
self.framework_failures = []
self.framework_warnings = []
+ self.expected_passes = []
self.unexpected_passes = []
self.unexpected_failures = []
self.unexpected_stat_failures = []
@@ -156,7 +168,7 @@ def getTestRun():
class TestOptions:
def __init__(self):
# skip this test?
- self.skip = 0
+ self.skip = False
# skip these ways
self.omit_ways = []
@@ -181,7 +193,7 @@ class TestOptions:
self.ignore_stderr = False
# Backpack test
- self.compile_backpack = 0
+ self.compile_backpack = False
# We sometimes want to modify the compiler_always_flags, so
# they are copied from config.compiler_always_flags when we
@@ -218,15 +230,15 @@ class TestOptions:
self.alone = False
# Does this test use a literate (.lhs) file?
- self.literate = 0
+ self.literate = False
# Does this test use a .c, .m or .mm file?
- self.c_src = 0
- self.objc_src = 0
- self.objcpp_src = 0
+ self.c_src = False
+ self.objc_src = False
+ self.objcpp_src = False
# Does this test use a .cmm file?
- self.cmm_src = 0
+ self.cmm_src = False
# Should we put .hi/.o files in a subdirectory?
self.outputdir = None
@@ -234,9 +246,6 @@ class TestOptions:
# Command to run before the test
self.pre_cmd = None
- # Command to run for extra cleaning
- self.clean_cmd = None
-
# Command wrapper: a function to apply to the command before running it
self.cmd_wrapper = None
diff --git a/testsuite/driver/testlib.py b/testsuite/driver/testlib.py
index 26e3d17679..ff6a8c8e74 100644
--- a/testsuite/driver/testlib.py
+++ b/testsuite/driver/testlib.py
@@ -3,13 +3,9 @@
# (c) Simon Marlow 2002
#
-from __future__ import print_function
-
import io
import shutil
import os
-import errno
-import string
import re
import traceback
import time
@@ -18,33 +14,30 @@ import copy
import glob
import sys
from math import ceil, trunc
+from pathlib import PurePath
import collections
import subprocess
-from testglobals import *
-from testutil import *
+from testglobals import config, ghc_env, default_testopts, brokens, t
+from testutil import strip_quotes, lndir, link_or_copy_file
extra_src_files = {'T4198': ['exitminus1.c']} # TODO: See #12223
+global pool_sema
if config.use_threads:
import threading
- try:
- import thread
- except ImportError: # Python 3
- import _thread as thread
+ pool_sema = threading.BoundedSemaphore(value=config.threads)
global wantToStop
wantToStop = False
-global pool_sema
-if config.use_threads:
- pool_sema = threading.BoundedSemaphore(value=config.threads)
-
def stopNow():
global wantToStop
wantToStop = True
+
def stopping():
return wantToStop
+
# Options valid for the current test only (these get reset to
# testdir_testopts after each test).
@@ -91,7 +84,7 @@ def normal( name, opts ):
return;
def skip( name, opts ):
- opts.skip = 1
+ opts.skip = True
def expect_fail( name, opts ):
# The compiler, testdriver, OS or platform is missing a certain
@@ -143,7 +136,8 @@ def _reqlib( name, opts, lib ):
cmd = strip_quotes(config.ghc_pkg)
p = subprocess.Popen([cmd, '--no-user-package-db', 'describe', lib],
stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ stderr=subprocess.PIPE,
+ env=ghc_env)
# read from stdout and stderr to avoid blocking due to
# buffers filling
p.communicate()
@@ -209,7 +203,6 @@ def _expect_broken_for( name, opts, bug, ways ):
opts.expect_fail_for = ways
def record_broken(name, opts, bug):
- global brokens
me = (bug, opts.testdir, name)
if not me in brokens:
brokens.append(me)
@@ -412,6 +405,12 @@ def compiler_profiled( ):
def compiler_debugged( ):
return config.compiler_debugged
+def have_gdb( ):
+ return config.have_gdb
+
+def have_readelf( ):
+ return config.have_readelf
+
# ---
def high_memory_usage(name, opts):
@@ -424,19 +423,19 @@ def multi_cpu_race(name, opts):
# ---
def literate( name, opts ):
- opts.literate = 1;
+ opts.literate = True
def c_src( name, opts ):
- opts.c_src = 1;
+ opts.c_src = True
def objc_src( name, opts ):
- opts.objc_src = 1;
+ opts.objc_src = True
def objcpp_src( name, opts ):
- opts.objcpp_src = 1;
+ opts.objcpp_src = True
def cmm_src( name, opts ):
- opts.cmm_src = 1;
+ opts.cmm_src = True
def outputdir( odir ):
return lambda name, opts, d=odir: _outputdir(name, opts, d)
@@ -454,12 +453,6 @@ def _pre_cmd( name, opts, cmd ):
# ----
-def clean_cmd( cmd ):
- # TODO. Remove all calls to clean_cmd.
- return lambda _name, _opts: None
-
-# ----
-
def cmd_prefix( prefix ):
return lambda name, opts, p=prefix: _cmd_prefix(name, opts, prefix)
@@ -497,7 +490,6 @@ def no_check_hp(name, opts):
def filter_stdout_lines( regex ):
""" Filter lines of stdout with the given regular expression """
- import re
def f( name, opts ):
_normalise_fun(name, opts, lambda s: '\n'.join(re.findall(regex, s)))
return f
@@ -520,6 +512,19 @@ def normalise_errmsg_fun( *fs ):
def _normalise_errmsg_fun( name, opts, *fs ):
opts.extra_errmsg_normaliser = join_normalisers(opts.extra_errmsg_normaliser, fs)
+def check_errmsg(needle):
+ def norm(str):
+ if needle in str:
+ return "%s contained in -ddump-simpl\n" % needle
+ else:
+ return "%s not contained in -ddump-simpl\n" % needle
+ return normalise_errmsg_fun(norm)
+
+def grep_errmsg(needle):
+ def norm(str):
+ return "".join(filter(lambda l: re.search(needle, l), str.splitlines(True)))
+ return normalise_errmsg_fun(norm)
+
def normalise_whitespace_fun(f):
return lambda name, opts: _normalise_whitespace_fun(name, opts, f)
@@ -607,8 +612,9 @@ def newTestDir(tempdir, dir):
testdir_suffix = '.run'
def _newTestDir(name, opts, tempdir, dir):
+ testdir = os.path.join('', *(p for p in PurePath(dir).parts if p != '..'))
opts.srcdir = os.path.join(os.getcwd(), dir)
- opts.testdir = os.path.join(tempdir, dir, name + testdir_suffix)
+ opts.testdir = os.path.join(tempdir, testdir, name + testdir_suffix)
opts.compiler_always_flags = config.compiler_always_flags
# -----------------------------------------------------------------------------
@@ -796,7 +802,7 @@ def do_test(name, way, func, args, files):
full_name = name + '(' + way + ')'
if_verbose(2, "=====> {0} {1} of {2} {3}".format(
- full_name, t.total_tests, len(allTestNames),
+ full_name, t.total_tests, len(allTestNames),
[len(t.unexpected_passes),
len(t.unexpected_failures),
len(t.framework_failures)]))
@@ -848,6 +854,7 @@ def do_test(name, way, func, args, files):
if exit_code != 0:
framework_fail(name, way, 'pre_cmd failed: {0}'.format(exit_code))
+ if_verbose(1, '** pre_cmd was "{0}". Running trace'.format(override_options(opts.pre_cmd)))
result = func(*[name,way] + args)
@@ -863,6 +870,7 @@ def do_test(name, way, func, args, files):
if passFail == 'pass':
if _expect_pass(way):
+ t.expected_passes.append((directory, name, way))
t.n_expected_passes += 1
else:
if_verbose(1, '*** unexpected pass for %s' % full_name)
@@ -948,8 +956,9 @@ def ghci_script( name, way, script):
# We pass HC and HC_OPTS as environment variables, so that the
# script can invoke the correct compiler by using ':! $HC $HC_OPTS'
- cmd = ('HC={{compiler}} HC_OPTS="{flags}" {{compiler}} {flags} {way_flags}'
+ cmd = ('HC={{compiler}} HC_OPTS="{flags}" {{compiler}} {way_flags} {flags}'
).format(flags=flags, way_flags=way_flags)
+ # NB: put way_flags before flags so that flags in all.T can overrie others
getTestOpts().stdin = script
return simple_run( name, way, cmd, getTestOpts().extra_run_opts )
@@ -964,19 +973,19 @@ def compile_fail( name, way, extra_hc_opts ):
return do_compile( name, way, 1, '', [], extra_hc_opts )
def backpack_typecheck( name, way, extra_hc_opts ):
- return do_compile( name, way, 0, '', [], "-fno-code -fwrite-interface " + extra_hc_opts, backpack=1 )
+ return do_compile( name, way, 0, '', [], "-fno-code -fwrite-interface " + extra_hc_opts, backpack=True )
def backpack_typecheck_fail( name, way, extra_hc_opts ):
- return do_compile( name, way, 1, '', [], "-fno-code -fwrite-interface " + extra_hc_opts, backpack=1 )
+ return do_compile( name, way, 1, '', [], "-fno-code -fwrite-interface " + extra_hc_opts, backpack=True )
def backpack_compile( name, way, extra_hc_opts ):
- return do_compile( name, way, 0, '', [], extra_hc_opts, backpack=1 )
+ return do_compile( name, way, 0, '', [], extra_hc_opts, backpack=True )
def backpack_compile_fail( name, way, extra_hc_opts ):
- return do_compile( name, way, 1, '', [], extra_hc_opts, backpack=1 )
+ return do_compile( name, way, 1, '', [], extra_hc_opts, backpack=True )
def backpack_run( name, way, extra_hc_opts ):
- return compile_and_run__( name, way, '', [], extra_hc_opts, backpack=1 )
+ return compile_and_run__( name, way, '', [], extra_hc_opts, backpack=True )
def multimod_compile( name, way, top_mod, extra_hc_opts ):
return do_compile( name, way, 0, top_mod, [], extra_hc_opts )
@@ -1206,7 +1215,7 @@ def simple_build(name, way, extra_hc_opts, should_fail, top_mod, link, addsuf, b
if config.verbose >= 1 and _expect_pass(way):
print('Compile failed (exit code {0}) errors were:'.format(exit_code))
actual_stderr_path = in_testdir(name, 'comp.stderr')
- if_verbose_dump(1, actual_stderr_path)
+ dump_file(actual_stderr_path)
# ToDo: if the sub-shell was killed by ^C, then exit
@@ -1415,7 +1424,7 @@ def stdout_ok(name, way):
expected_stdout_file, actual_stdout_file)
def dump_stdout( name ):
- with open(in_testdir(name, 'run.stdout')) as f:
+ with open(in_testdir(name, 'run.stdout'), encoding='utf8') as f:
str = f.read().strip()
if str:
print("Stdout (", name, "):")
@@ -1431,7 +1440,7 @@ def stderr_ok(name, way):
whitespace_normaliser=normalise_whitespace)
def dump_stderr( name ):
- with open(in_testdir(name, 'run.stderr')) as f:
+ with open(in_testdir(name, 'run.stderr'), encoding='utf8') as f:
str = f.read().strip()
if str:
print("Stderr (", name, "):")
@@ -1553,7 +1562,7 @@ def compare_outputs(way, kind, normaliser, expected_file, actual_file,
# See Note [Output comparison].
if whitespace_normaliser(expected_str) == whitespace_normaliser(actual_str):
- return 1
+ return True
else:
if config.verbose >= 1 and _expect_pass(way):
print('Actual ' + kind + ' output differs from expected:')
@@ -1568,29 +1577,39 @@ def compare_outputs(way, kind, normaliser, expected_file, actual_file,
# See Note [Output comparison].
r = runCmd('diff -uw "{0}" "{1}"'.format(expected_normalised_path,
actual_normalised_path),
- print_output = 1)
+ print_output=True)
# If for some reason there were no non-whitespace differences,
# then do a full diff
if r == 0:
r = runCmd('diff -u "{0}" "{1}"'.format(expected_normalised_path,
actual_normalised_path),
- print_output = 1)
+ print_output=True)
if config.accept and (getTestOpts().expect == 'fail' or
way in getTestOpts().expect_fail_for):
if_verbose(1, 'Test is expected to fail. Not accepting new output.')
- return 0
+ return False
elif config.accept and actual_raw:
- if_verbose(1, 'Accepting new output.')
+ if config.accept_platform:
+ if_verbose(1, 'Accepting new output for platform "'
+ + config.platform + '".')
+ expected_path += '-' + config.platform
+ elif config.accept_os:
+ if_verbose(1, 'Accepting new output for os "'
+ + config.os + '".')
+ expected_path += '-' + config.os
+ else:
+ if_verbose(1, 'Accepting new output.')
+
write_file(expected_path, actual_raw)
- return 1
+ return True
elif config.accept:
if_verbose(1, 'No output. Deleting "{0}".'.format(expected_path))
os.remove(expected_path)
- return 1
+ return True
else:
- return 0
+ return False
# Note [Output comparison]
#
@@ -1610,7 +1629,7 @@ def compare_outputs(way, kind, normaliser, expected_file, actual_file,
def normalise_whitespace( str ):
# Merge contiguous whitespace characters into a single space.
- return ' '.join(w for w in str.split())
+ return ' '.join(str.split())
callSite_re = re.compile(r', called at (.+):[\d]+:[\d]+ in [\w\-\.]+:')
@@ -1730,6 +1749,7 @@ def normalise_prof (str):
def normalise_slashes_( str ):
str = re.sub('\\\\', '/', str)
+ str = re.sub('//', '/', str)
return str
def normalise_exe_( str ):
@@ -1773,15 +1793,14 @@ def if_verbose( n, s ):
if config.verbose >= n:
print(s)
-def if_verbose_dump( n, f ):
- if config.verbose >= n:
- try:
- with io.open(f) as file:
- print(file.read())
- except Exception:
- print('')
+def dump_file(f):
+ try:
+ with io.open(f) as file:
+ print(file.read())
+ except Exception:
+ print('')
-def runCmd(cmd, stdin=None, stdout=None, stderr=None, timeout_multiplier=1.0, print_output=0):
+def runCmd(cmd, stdin=None, stdout=None, stderr=None, timeout_multiplier=1.0, print_output=False):
timeout_prog = strip_quotes(config.timeout_prog)
timeout = str(int(ceil(config.timeout * timeout_multiplier)))
@@ -1789,9 +1808,6 @@ def runCmd(cmd, stdin=None, stdout=None, stderr=None, timeout_multiplier=1.0, pr
cmd = cmd.format(**config.__dict__)
if_verbose(3, cmd + ('< ' + os.path.basename(stdin) if stdin else ''))
- # declare the buffers to a default
- stdin_buffer = None
-
stdin_file = io.open(stdin, 'rb') if stdin else None
stdout_buffer = b''
stderr_buffer = b''
@@ -1809,13 +1825,14 @@ def runCmd(cmd, stdin=None, stdout=None, stderr=None, timeout_multiplier=1.0, pr
r = subprocess.Popen([timeout_prog, timeout, cmd],
stdin=stdin_file,
stdout=subprocess.PIPE,
- stderr=hStdErr)
+ stderr=hStdErr,
+ env=ghc_env)
stdout_buffer, stderr_buffer = r.communicate()
finally:
if stdin_file:
stdin_file.close()
- if config.verbose >= 1 and print_output >= 1:
+ if config.verbose >= 1 and print_output:
if stdout_buffer:
sys.stdout.buffer.write(stdout_buffer)
if stderr_buffer:
@@ -1848,7 +1865,7 @@ def gsNotWorking():
print("GhostScript not available for hp2ps tests")
global gs_working
-gs_working = 0
+gs_working = False
if config.have_profiling:
if config.gs != '':
resultGood = runCmd(genGSCmd(config.confdir + '/good.ps'));
@@ -1857,7 +1874,7 @@ if config.have_profiling:
' >/dev/null 2>&1')
if resultBad != 0:
print("GhostScript available for hp2ps tests")
- gs_working = 1;
+ gs_working = True
else:
gsNotWorking();
else:
@@ -1897,7 +1914,7 @@ def in_srcdir(name, suffix=''):
# Finding the sample output. The filename is of the form
#
-# <test>.stdout[-ws-<wordsize>][-<platform>]
+# <test>.stdout[-ws-<wordsize>][-<platform>|-<os>]
#
def find_expected_file(name, suff):
basename = add_suffix(name, suff)
@@ -1914,7 +1931,6 @@ def find_expected_file(name, suff):
if config.msys:
import stat
- import time
def cleanup():
testdir = getTestOpts().testdir
max_attempts = 5
@@ -1968,7 +1984,7 @@ def findTFiles(roots):
for root in roots:
for path, dirs, files in os.walk(root, topdown=True):
# Never pick up .T files in uncleaned .run directories.
- dirs[:] = [dir for dir in sorted(dirs)
+ dirs[:] = [dir for dir in sorted(dirs)
if not dir.endswith(testdir_suffix)]
for filename in files:
if filename.endswith('.T'):
diff --git a/testsuite/driver/testutil.py b/testsuite/driver/testutil.py
index dcba1777d1..15587e6960 100644
--- a/testsuite/driver/testutil.py
+++ b/testsuite/driver/testutil.py
@@ -1,4 +1,3 @@
-import errno
import os
import platform
import subprocess
@@ -11,8 +10,7 @@ def strip_quotes(s):
return s.strip('\'"')
def getStdout(cmd_and_args):
- # Can't use subprocess.check_output as it's not available in Python 2.6;
- # It's also not quite the same as check_output, since we also verify that
+ # Can't use subprocess.check_output, since we also verify that
# no stderr was produced
p = subprocess.Popen([strip_quotes(cmd_and_args[0])] + cmd_and_args[1:],
stdout=subprocess.PIPE,
@@ -23,16 +21,7 @@ def getStdout(cmd_and_args):
raise Exception("Command failed: " + str(cmd_and_args))
if stderr:
raise Exception("stderr from command: %s\nOutput:\n%s\n" % (cmd_and_args, stderr))
- return stdout
-
-def mkdirp(path):
- try:
- os.makedirs(path)
- except OSError as e:
- if e.errno == errno.EEXIST and os.path.isdir(path):
- pass
- else:
- raise
+ return stdout.decode('utf-8')
def lndir(srcdir, dstdir):
# Create symlinks for all files in src directory.
@@ -60,10 +49,6 @@ else:
link_or_copy_file = os.symlink
class Watcher(object):
- global pool
- global evt
- global sync_lock
-
def __init__(self, count):
self.pool = count
self.evt = threading.Event()