ghc-dup: d24c5e8a11204e433b3ab0e114689da476fec5ae

     1: #
     2: # (c) Simon Marlow 2002
     3: #
     4: 
     5: # This allows us to use the "with X:" syntax with python 2.5:
     6: from __future__ import with_statement
     7: 
     8: import sys
     9: import os
    10: import errno
    11: import string
    12: import re
    13: import traceback
    14: import copy
    15: import glob
    16: import types
    17: 
    18: have_subprocess = False
    19: try:
    20:     import subprocess
    21:     have_subprocess = True
    22: except:
    23:     print "Warning: subprocess not found, will fall back to spawnv"
    24: 
    25: from string import join
    26: from testglobals import *
    27: from testutil import *
    28: 
    29: if config.use_threads:
    30:     import threading
    31:     import thread
    32: 
    33: # Options valid for all the tests in the current "directory".  After
    34: # each test, we reset the options to these.  To change the options for
    35: # multiple tests, the function setTestOpts() below can be used to alter
    36: # these options.
    37: global thisdir_testopts
    38: thisdir_testopts = TestOptions()
    39: 
    40: def getThisDirTestOpts():
    41:     return thisdir_testopts
    42: 
    43: # Options valid for the current test only (these get reset to
    44: # testdir_testopts after each test).
    45: 
    46: global testopts_local
    47: if config.use_threads:
    48:     testopts_local = threading.local()
    49: else:
    50:     class TestOpts_Local:
    51:         pass
    52:     testopts_local = TestOpts_Local()
    53: 
    54: def getTestOpts():
    55:     return testopts_local.x
    56: 
    57: def setLocalTestOpts(opts):
    58:     global testopts_local
    59:     testopts_local.x=opts
    60: 
    61: # This can be called at the top of a file of tests, to set default test options
    62: # for the following tests.
    63: def setTestOpts( f ):
    64:     f( thisdir_testopts );
    65: 
    66: # -----------------------------------------------------------------------------
    67: # Canned setup functions for common cases.  eg. for a test you might say
    68: #
    69: #      test('test001', normal, compile, [''])
    70: #
    71: # to run it without any options, but change it to
    72: #
    73: #      test('test001', expect_fail, compile, [''])
    74: #
    75: # to expect failure for this test.
    76: 
    77: def normal( opts ):
    78:     return;
    79: 
    80: def skip( opts ):
    81:     opts.skip = 1
    82: 
    83: def expect_fail( opts ):
    84:     opts.expect = 'fail';
    85: 
    86: def reqlib( lib ):
    87:     return lambda opts, l=lib: _reqlib (opts, l )
    88: 
    89: # Cache the results of looking to see if we have a library or not.
    90: # This makes quite a difference, especially on Windows.
    91: have_lib = {}
    92: 
    93: def _reqlib( opts, lib ):
    94:     if have_lib.has_key(lib):
    95:         got_it = have_lib[lib]
    96:     else:
    97:         if have_subprocess:
    98:             # By preference we use subprocess, as the alternative uses
    99:             # /dev/null which mingw doesn't have.
   100:             p = subprocess.Popen([config.ghc_pkg, '--no-user-package-db', 'describe', lib],
   101:                                  stdout=subprocess.PIPE,
   102:                                  stderr=subprocess.PIPE)
   103:             # read from stdout and stderr to avoid blocking due to
   104:             # buffers filling
   105:             p.communicate()
   106:             r = p.wait()
   107:         else:
   108:             r = os.system(config.ghc_pkg + ' describe ' + lib
   109:                                          + ' > /dev/null 2> /dev/null')
   110:         got_it = r == 0
   111:         have_lib[lib] = got_it
   112: 
   113:     if not got_it:
   114:         opts.expect = 'missing-lib'
   115: 
   116: def req_profiling( opts ):
   117:     if not config.have_profiling:
   118:         opts.expect = 'fail'
   119: 
   120: def req_shared_libs( opts ):
   121:     if not config.have_shared_libs:
   122:         opts.expect = 'fail'
   123: 
   124: def req_interp( opts ):
   125:     if not config.have_interp:
   126:         opts.expect = 'fail'
   127: 
   128: def req_smp( opts ):
   129:     if not config.have_smp:
   130:         opts.expect = 'fail'
   131: 
   132: def expect_broken( bug ):
   133:     return lambda opts, b=bug: _expect_broken (opts, b )
   134: 
   135: def _expect_broken( opts, bug ):
   136:     opts.expect = 'fail';
   137: 
   138: def ignore_output( opts ):
   139:     opts.ignore_output = 1
   140: 
   141: def no_stdin( opts ):
   142:     opts.no_stdin = 1
   143: 
   144: def combined_output( opts ):
   145:     opts.combined_output = True
   146: 
   147: # -----
   148: 
   149: def expect_fail_for( ways ):
   150:     return lambda opts, w=ways: _expect_fail_for( opts, w )
   151: 
   152: def _expect_fail_for( opts, ways ):
   153:     opts.expect_fail_for = ways
   154: 
   155: def expect_broken_for( bug, ways ):
   156:     return lambda opts, b=bug, w=ways: _expect_broken_for( opts, b, w )
   157: 
   158: def _expect_broken_for( opts, bug, ways ):
   159:     opts.expect_fail_for = ways
   160: 
   161: # -----
   162: 
   163: def omit_ways( ways ):
   164:     return lambda opts, w=ways: _omit_ways( opts, w )
   165: 
   166: def _omit_ways( opts, ways ):
   167:     opts.omit_ways = ways
   168: 
   169: # -----
   170: 
   171: def only_ways( ways ):
   172:     return lambda opts, w=ways: _only_ways( opts, w )
   173: 
   174: def _only_ways( opts, ways ):
   175:     opts.only_ways = ways
   176: 
   177: # -----
   178: 
   179: def extra_ways( ways ):
   180:     return lambda opts, w=ways: _extra_ways( opts, w )
   181: 
   182: def _extra_ways( opts, ways ):
   183:     opts.extra_ways = ways
   184: 
   185: # -----
   186: 
   187: def omit_compiler_types( compiler_types ):
   188:    return lambda opts, c=compiler_types: _omit_compiler_types(opts, c)
   189: 
   190: def _omit_compiler_types( opts, compiler_types ):
   191:     if config.compiler_type in compiler_types:
   192:         opts.skip = 1
   193: 
   194: # -----
   195: 
   196: def only_compiler_types( compiler_types ):
   197:    return lambda opts, c=compiler_types: _only_compiler_types(opts, c)
   198: 
   199: def _only_compiler_types( opts, compiler_types ):
   200:     if config.compiler_type not in compiler_types:
   201:         opts.skip = 1
   202: 
   203: # -----
   204: 
   205: def set_stdin( file ):
   206:    return lambda opts, f=file: _set_stdin(opts, f);
   207: 
   208: def _set_stdin( opts, f ):
   209:    opts.stdin = f
   210: 
   211: # -----
   212: 
   213: def exit_code( val ):
   214:     return lambda opts, v=val: _exit_code(opts, v);
   215: 
   216: def _exit_code( opts, v ):
   217:     opts.exit_code = v
   218: 
   219: # -----
   220: 
   221: def extra_run_opts( val ):
   222:     return lambda opts, v=val: _extra_run_opts(opts, v);
   223: 
   224: def _extra_run_opts( opts, v ):
   225:     opts.extra_run_opts = v
   226: 
   227: # -----
   228: 
   229: def extra_hc_opts( val ):
   230:     return lambda opts, v=val: _extra_hc_opts(opts, v);
   231: 
   232: def _extra_hc_opts( opts, v ):
   233:     opts.extra_hc_opts = v
   234: 
   235: # -----
   236: 
   237: def extra_clean( files ):
   238:     return lambda opts, v=files: _extra_clean(opts, v);
   239: 
   240: def _extra_clean( opts, v ):
   241:     opts.clean_files = v
   242: 
   243: # -----
   244: 
   245: def stats_num_field( field, min, max ):
   246:     return lambda opts, f=field, x=min, y=max: _stats_num_field(opts, f, x, y);
   247: 
   248: def _stats_num_field( opts, f, x, y ):
   249:     # copy the dictionary, as the config gets shared between all tests
   250:     opts.stats_num_fields = opts.stats_num_fields.copy()
   251:     opts.stats_num_fields[f] = (x, y)
   252: 
   253: def compiler_stats_num_field( field, min, max ):
   254:     return lambda opts, f=field, x=min, y=max: _compiler_stats_num_field(opts, f, x, y);
   255: 
   256: def _compiler_stats_num_field( opts, f, x, y ):
   257:     # copy the dictionary, as the config gets shared between all tests
   258:     opts.compiler_stats_num_fields = opts.compiler_stats_num_fields.copy()
   259:     opts.compiler_stats_num_fields[f] = (x, y)
   260: 
   261: # -----
   262: 
   263: def stats_range_field( field, min, max ):
   264:     return lambda opts, f=field, x=min, y=max: _stats_range_field(opts, f, x, y);
   265: 
   266: def _stats_range_field( opts, f, x, y ):
   267:     # copy the dictionary, as the config gets shared between all tests
   268:     opts.stats_range_fields = opts.stats_range_fields.copy()
   269:     opts.stats_range_fields[f] = (x, y)
   270: 
   271: def compiler_stats_range_field( field, min, max ):
   272:     return lambda opts, f=field, x=min, y=max: _compiler_stats_range_field(opts, f, x, y);
   273: 
   274: def _compiler_stats_range_field( opts, f, x, y ):
   275:     # copy the dictionary, as the config gets shared between all tests
   276:     opts.compiler_stats_range_fields = opts.compiler_stats_range_fields.copy()
   277:     opts.compiler_stats_range_fields[f] = (x, y)
   278: 
   279: # -----
   280: 
   281: def skip_if_no_ghci(opts):
   282:     if not ('ghci' in config.run_ways):
   283:         opts.skip = 1
   284: 
   285: # ----
   286: 
   287: def skip_if_fast(opts):
   288:     if config.fast:
   289:         opts.skip = 1
   290: 
   291: # -----
   292: 
   293: def if_platform( plat, f ):
   294:     if config.platform == plat:
   295:         return f
   296:     else:
   297:         return normal
   298: 
   299: def if_not_platform( plat, f ):
   300:     if config.platform != plat:
   301:         return f
   302:     else:
   303:         return normal
   304: 
   305: def if_os( os, f ):
   306:     if config.os == os:
   307:         return f
   308:     else:
   309:         return normal
   310: 
   311: def unless_os( os, f ):
   312:     if config.os == os:
   313:         return normal
   314:     else:
   315:         return f
   316: 
   317: def if_arch( arch, f ):
   318:     if config.arch == arch:
   319:         return f
   320:     else:
   321:         return normal
   322: 
   323: def if_wordsize( ws, f ):
   324:     if config.wordsize == str(ws):
   325:         return f
   326:     else:
   327:         return normal
   328: 
   329: def if_msys( f ):
   330:     if config.msys:
   331:         return f
   332:     else:
   333:         return normal
   334: 
   335: def if_cygwin( f ):
   336:     if config.cygwin:
   337:         return f
   338:     else:
   339:         return normal
   340: 
   341: # ---
   342: 
   343: def if_in_tree_compiler( f ):
   344:     if config.in_tree_compiler:
   345:         return f
   346:     else:
   347:         return normal
   348: 
   349: def unless_in_tree_compiler( f ):
   350:     if config.in_tree_compiler:
   351:         return normal
   352:     else:
   353:         return f
   354: 
   355: def if_compiler_type( compiler, f ):
   356:     if config.compiler_type == compiler:
   357:         return f
   358:     else:
   359:         return normal
   360: 
   361: def if_compiler_profiled( f ):
   362:     if config.compiler_profiled:
   363:         return f
   364:     else:
   365:         return normal
   366: 
   367: def unless_compiler_profiled( f ):
   368:     if config.compiler_profiled:
   369:         return normal
   370:     else:
   371:         return f
   372: 
   373: def if_compiler_lt( compiler, version, f ):
   374:     if config.compiler_type == compiler and \
   375:        version_lt(config.compiler_version, version):
   376:         return f
   377:     else:
   378:         return normal
   379: 
   380: def if_compiler_le( compiler, version, f ):
   381:     if config.compiler_type == compiler and \
   382:        version_le(config.compiler_version, version):
   383:         return f
   384:     else:
   385:         return normal
   386: 
   387: def if_compiler_gt( compiler, version, f ):
   388:     if config.compiler_type == compiler and \
   389:        version_gt(config.compiler_version, version):
   390:         return f
   391:     else:
   392:         return normal
   393: 
   394: def if_compiler_ge( compiler, version, f ):
   395:     if config.compiler_type == compiler and \
   396:        version_ge(config.compiler_version, version):
   397:         return f
   398:     else:
   399:         return normal
   400: 
   401: def namebase( nb ):
   402:    return lambda opts, nb=nb: _namebase(opts, nb)
   403: 
   404: def _namebase( opts, nb ):
   405:     opts.with_namebase = nb
   406: 
   407: # ---
   408: 
   409: def if_tag( tag, f ):
   410:     if tag in config.compiler_tags:
   411:         return f
   412:     else:
   413:         return normal
   414: 
   415: def unless_tag( tag, f ):
   416:     if not (tag in config.compiler_tags):
   417:         return f
   418:     else:
   419:         return normal
   420: 
   421: # ---
   422: def alone(opts):
   423:     opts.alone = True
   424: 
   425: # ---
   426: def literate( opts ):
   427:     opts.literate = 1;
   428: 
   429: def c_src( opts ):
   430:     opts.c_src = 1;
   431: 
   432: def objc_src( opts ):
   433:     opts.objc_src = 1;
   434: 
   435: def objcpp_src( opts ):
   436:     opts.objcpp_src = 1;
   437: 
   438: # ----
   439: 
   440: def pre_cmd( cmd ):
   441:     return lambda opts, c=cmd: _pre_cmd(opts, cmd)
   442: 
   443: def _pre_cmd( opts, cmd ):
   444:     opts.pre_cmd = cmd
   445: 
   446: # ----
   447: 
   448: def clean_cmd( cmd ):
   449:     return lambda opts, c=cmd: _clean_cmd(opts, cmd)
   450: 
   451: def _clean_cmd( opts, cmd ):
   452:     opts.clean_cmd = cmd
   453: 
   454: # ----
   455: 
   456: def cmd_prefix( prefix ):
   457:     return lambda opts, p=prefix: _cmd_prefix(opts, prefix)
   458: 
   459: def _cmd_prefix( opts, prefix ):
   460:     opts.cmd_wrapper = lambda cmd, p=prefix: p + ' ' + cmd;
   461: 
   462: # ----
   463: 
   464: def cmd_wrapper( fun ):
   465:     return lambda opts, f=fun: _cmd_wrapper(opts, fun)
   466: 
   467: def _cmd_wrapper( opts, fun ):
   468:     opts.cmd_wrapper = fun
   469: 
   470: # ----
   471: 
   472: def compile_cmd_prefix( prefix ):
   473:     return lambda opts, p=prefix: _compile_cmd_prefix(opts, prefix)
   474: 
   475: def _compile_cmd_prefix( opts, prefix ):
   476:     opts.compile_cmd_prefix = prefix
   477: 
   478: # ----
   479: 
   480: def normalise_slashes( opts ):
   481:     opts.extra_normaliser = normalise_slashes_
   482: 
   483: def normalise_exe( opts ):
   484:     opts.extra_normaliser = normalise_exe_
   485: 
   486: def normalise_fun( fun ):
   487:     return lambda opts, f=fun: _normalise_fun(opts, f)
   488: 
   489: def _normalise_fun( opts, f ):
   490:     opts.extra_normaliser = f
   491: 
   492: def normalise_errmsg_fun( fun ):
   493:     return lambda opts, f=fun: _normalise_errmsg_fun(opts, f)
   494: 
   495: def _normalise_errmsg_fun( opts, f ):
   496:     opts.extra_errmsg_normaliser = f
   497: 
   498: def two_normalisers(f, g):
   499:     return lambda x, f=f, g=g: f(g(x))
   500: 
   501: # ----
   502: # Function for composing two opt-fns together
   503: 
   504: def composes( fs ):
   505:     return reduce(lambda f, g: compose(f, g), fs)
   506: 
   507: def compose( f, g ):
   508:     return lambda opts, f=f, g=g: _compose(opts,f,g)
   509: 
   510: def _compose( opts, f, g ):
   511:     f(opts)
   512:     g(opts)
   513: 
   514: # -----------------------------------------------------------------------------
   515: # The current directory of tests
   516: 
   517: def newTestDir( dir ):
   518:     global thisdir_testopts
   519:     # reset the options for this test directory
   520:     thisdir_testopts = copy.copy(default_testopts)
   521:     thisdir_testopts.testdir = dir
   522:     thisdir_testopts.compiler_always_flags = config.compiler_always_flags
   523: 
   524: # -----------------------------------------------------------------------------
   525: # Actually doing tests
   526: 
   527: allTests = []
   528: allTestNames = set([])
   529: 
   530: def runTest (opts, name, setup, func, args):
   531:     n = 1
   532: 
   533:     if type(setup) is types.ListType:
   534:        setup = composes(setup)
   535: 
   536:     setup(opts)
   537: 
   538:     if opts.alone:
   539:         n = config.threads
   540: 
   541:     ok = 0
   542: 
   543:     if config.use_threads:
   544:         t.thread_pool.acquire()
   545:         try:
   546:             while config.threads<(t.running_threads+n):
   547:                 t.thread_pool.wait()
   548:             t.running_threads = t.running_threads+n
   549:             ok=1
   550:             t.thread_pool.release()
   551:             thread.start_new_thread(test_common_thread, (n, name, opts, func, args))
   552:         except:
   553:             if not ok:
   554:                 t.thread_pool.release()
   555:     else:
   556:         test_common_work (name, opts, func, args)
   557: 
   558: # name  :: String
   559: # setup :: TestOpts -> IO ()
   560: def test (name, setup, func, args):
   561:     global allTests
   562:     global allTestNames
   563:     if name in allTestNames:
   564:         framework_fail(name, 'duplicate', 'There are multiple tests with this name')
   565:     myTestOpts = copy.copy(thisdir_testopts)
   566:     allTests += [lambda : runTest(myTestOpts, name, setup, func, args)]
   567:     allTestNames.add(name)
   568: 
   569: if config.use_threads:
   570:     def test_common_thread(n, name, opts, func, args):
   571:         t.lock.acquire()
   572:         try:
   573:             test_common_work(name,opts,func,args)
   574:         finally:
   575:             t.lock.release()
   576:             t.thread_pool.acquire()
   577:             t.running_threads = t.running_threads - n
   578:             t.thread_pool.notify()
   579:             t.thread_pool.release()
   580: 
   581: def get_package_cache_timestamp():
   582:     if config.package_conf_cache_file == '':
   583:         return 0.0
   584:     else:
   585:         try:
   586:             return os.stat(config.package_conf_cache_file).st_mtime
   587:         except:
   588:             return 0.0
   589: 
   590: 
   591: def test_common_work (name, opts, func, args):
   592:     try:
   593:         t.total_tests = t.total_tests+1
   594:         setLocalTestOpts(opts)
   595: 
   596:         package_conf_cache_file_start_timestamp = get_package_cache_timestamp()
   597: 
   598:         # All the ways we might run this test
   599:         if func == compile or func == multimod_compile:
   600:             all_ways = config.compile_ways
   601:         elif func == compile_and_run or func == multimod_compile_and_run:
   602:             all_ways = config.run_ways
   603:         elif func == ghci_script:
   604:             if 'ghci' in config.run_ways:
   605:                 all_ways = ['ghci']
   606:             else:
   607:                 all_ways = []
   608:         else:
   609:             all_ways = ['normal']
   610: 
   611:         # A test itself can request extra ways by setting opts.extra_ways
   612:         all_ways = all_ways + filter(lambda way: way not in all_ways,
   613:                                      opts.extra_ways)
   614: 
   615:         t.total_test_cases = t.total_test_cases + len(all_ways)
   616: 
   617:         ok_way = lambda way: \
   618:             not getTestOpts().skip \
   619:             and (config.only == [] or name in config.only) \
   620:             and (getTestOpts().only_ways == None or way in getTestOpts().only_ways) \
   621:             and (config.cmdline_ways == [] or way in config.cmdline_ways) \
   622:             and way not in getTestOpts().omit_ways
   623: 
   624:         # Which ways we are asked to skip
   625:         do_ways = filter (ok_way,all_ways)
   626: 
   627:         # In fast mode, we skip all but one way
   628:         if config.fast and len(do_ways) > 0:
   629:             do_ways = [do_ways[0]]
   630: 
   631:         if not config.clean_only:
   632:             # Run the required tests...
   633:             for way in do_ways:
   634:                 do_test (name, way, func, args)
   635: 
   636:             for way in all_ways:
   637:                 if way not in do_ways:
   638:                     skiptest (name,way)
   639: 
   640:         if getTestOpts().cleanup != '' and (config.clean_only or do_ways != []):
   641:             clean(map (lambda suff: name + suff,
   642:                       ['', '.exe', '.exe.manifest', '.genscript',
   643:                        '.stderr.normalised',        '.stdout.normalised',
   644:                        '.run.stderr',               '.run.stdout',
   645:                        '.run.stderr.normalised',    '.run.stdout.normalised',
   646:                        '.comp.stderr',              '.comp.stdout',
   647:                        '.comp.stderr.normalised',   '.comp.stdout.normalised',
   648:                        '.interp.stderr',            '.interp.stdout',
   649:                        '.interp.stderr.normalised', '.interp.stdout.normalised',
   650:                        '.stats', '.comp.stats',
   651:                        '.hi', '.o', '.prof', '.exe.prof', '.hc',
   652:                        '_stub.h', '_stub.c', '_stub.o',
   653:                        '.hp', '.exe.hp', '.ps', '.aux', '.hcr', '.eventlog']))
   654: 
   655:             if func == multi_compile or func == multi_compile_fail:
   656:                     extra_mods = args[1]
   657:                     clean(map (lambda (f,x): replace_suffix(f, 'o'), extra_mods))
   658:                     clean(map (lambda (f,x): replace_suffix(f, 'hi'), extra_mods))
   659: 
   660:             clean(getTestOpts().clean_files)
   661: 
   662:             try:
   663:                 cleanCmd = getTestOpts().clean_cmd
   664:                 if cleanCmd != None:
   665:                     result = runCmdFor(name, 'cd ' + getTestOpts().testdir + ' && ' + cleanCmd)
   666:                     if result != 0:
   667:                         framework_fail(name, 'cleaning', 'clean-command failed: ' + str(result))
   668:             except e:
   669:                 framework_fail(name, 'cleaning', 'clean-command exception')
   670: 
   671:         package_conf_cache_file_end_timestamp = get_package_cache_timestamp();
   672: 
   673:         if package_conf_cache_file_start_timestamp != package_conf_cache_file_end_timestamp:
   674:             framework_fail(name, 'whole-test', 'Package cache timestamps do not match: ' + str(package_conf_cache_file_start_timestamp) + ' ' + str(package_conf_cache_file_end_timestamp))
   675: 
   676:         try:
   677:             for f in files_written[name]:
   678:                 if os.path.exists(f):
   679:                     try:
   680:                         if not f in files_written_not_removed[name]:
   681:                             files_written_not_removed[name].append(f)
   682:                     except:
   683:                         files_written_not_removed[name] = [f]
   684:         except:
   685:             pass
   686:     except Exception, e:
   687:         framework_fail(name, 'runTest', 'Unhandled exception: ' + str(e))
   688: 
   689: def clean(strs):
   690:     for str in strs:
   691:         for name in glob.glob(in_testdir(str)):
   692:             clean_full_path(name)
   693: 
   694: def clean_full_path(name):
   695:         try:
   696:             # Remove files...
   697:             os.remove(name)
   698:         except OSError, e1:
   699:             try:
   700:                 # ... and empty directories
   701:                 os.rmdir(name)
   702:             except OSError, e2:
   703:                 # We don't want to fail here, but we do want to know
   704:                 # what went wrong, so print out the exceptions.
   705:                 # ENOENT isn't a problem, though, as we clean files
   706:                 # that don't necessarily exist.
   707:                 if e1.errno != errno.ENOENT:
   708:                     print e1
   709:                 if e2.errno != errno.ENOENT:
   710:                     print e2
   711: 
   712: def do_test(name, way, func, args):
   713:     full_name = name + '(' + way + ')'
   714: 
   715:     try:
   716:         print '=====>', full_name, t.total_tests, 'of', len(allTests), \
   717:                         str([t.n_unexpected_passes,   \
   718:                              t.n_unexpected_failures, \
   719:                              t.n_framework_failures])
   720: 
   721:         if config.use_threads:
   722:             t.lock.release()
   723: 
   724:         try:
   725:             preCmd = getTestOpts().pre_cmd
   726:             if preCmd != None:
   727:                 result = runCmdFor(name, 'cd ' + getTestOpts().testdir + ' && ' + preCmd)
   728:                 if result != 0:
   729:                     framework_fail(name, way, 'pre-command failed: ' + str(result))
   730:         except e:
   731:             framework_fail(name, way, 'pre-command exception')
   732: 
   733:         try:
   734:             result = apply(func, [name,way] + args)
   735:         finally:
   736:             if config.use_threads:
   737:                 t.lock.acquire()
   738: 
   739:         if getTestOpts().expect != 'pass' and \
   740:                 getTestOpts().expect != 'fail' and \
   741:                 getTestOpts().expect != 'missing-lib':
   742:             framework_fail(name, way, 'bad expected ' + getTestOpts().expect)
   743: 
   744:         try:
   745:             passFail = result['passFail']
   746:         except:
   747:             passFail = 'No passFail found'
   748: 
   749:         if passFail == 'pass':
   750:             if getTestOpts().expect == 'pass' \
   751:                and way not in getTestOpts().expect_fail_for:
   752:                 t.n_expected_passes = t.n_expected_passes + 1
   753:                 if name in t.expected_passes:
   754:                     t.expected_passes[name].append(way)
   755:                 else:
   756:                     t.expected_passes[name] = [way]
   757:             else:
   758:                 print '*** unexpected pass for', full_name
   759:                 t.n_unexpected_passes = t.n_unexpected_passes + 1
   760:                 addPassingTestInfo(t.unexpected_passes, getTestOpts().testdir, name, way)
   761:         elif passFail == 'fail':
   762:             if getTestOpts().expect == 'pass' \
   763:                and way not in getTestOpts().expect_fail_for:
   764:                 print '*** unexpected failure for', full_name
   765:                 t.n_unexpected_failures = t.n_unexpected_failures + 1
   766:                 reason = result['reason']
   767:                 addFailingTestInfo(t.unexpected_failures, getTestOpts().testdir, name, reason, way)
   768:             else:
   769:                 if getTestOpts().expect == 'missing-lib':
   770:                     t.n_missing_libs = t.n_missing_libs + 1
   771:                     if name in t.missing_libs:
   772:                         t.missing_libs[name].append(way)
   773:                     else:
   774:                         t.missing_libs[name] = [way]
   775:                 else:
   776:                     t.n_expected_failures = t.n_expected_failures + 1
   777:                     if name in t.expected_failures:
   778:                         t.expected_failures[name].append(way)
   779:                     else:
   780:                         t.expected_failures[name] = [way]
   781:         else:
   782:             framework_fail(name, way, 'bad result ' + passFail)
   783:     except:
   784:         framework_fail(name, way, 'do_test exception')
   785:         traceback.print_exc()
   786: 
   787: def addPassingTestInfo (testInfos, directory, name, way):
   788:     directory = re.sub('^\\.[/\\\\]', '', directory)
   789: 
   790:     if not directory in testInfos:
   791:         testInfos[directory] = {}
   792: 
   793:     if not name in testInfos[directory]:
   794:         testInfos[directory][name] = []
   795: 
   796:     testInfos[directory][name].append(way)
   797: 
   798: def addFailingTestInfo (testInfos, directory, name, reason, way):
   799:     directory = re.sub('^\\.[/\\\\]', '', directory)
   800: 
   801:     if not directory in testInfos:
   802:         testInfos[directory] = {}
   803: 
   804:     if not name in testInfos[directory]:
   805:         testInfos[directory][name] = {}
   806: 
   807:     if not reason in testInfos[directory][name]:
   808:         testInfos[directory][name][reason] = []
   809: 
   810:     testInfos[directory][name][reason].append(way)
   811: 
   812: def skiptest (name, way):
   813:     # print 'Skipping test \"', name, '\"'
   814:     t.n_tests_skipped = t.n_tests_skipped + 1
   815:     if name in t.tests_skipped:
   816:         t.tests_skipped[name].append(way)
   817:     else:
   818:         t.tests_skipped[name] = [way]
   819: 
   820: def framework_fail( name, way, reason ):
   821:     full_name = name + '(' + way + ')'
   822:     print '*** framework failure for', full_name, reason, ':'
   823:     t.n_framework_failures = t.n_framework_failures + 1
   824:     if name in t.framework_failures:
   825:         t.framework_failures[name].append(way)
   826:     else:
   827:         t.framework_failures[name] = [way]
   828: 
   829: def badResult(result):
   830:     try:
   831:         if result['passFail'] == 'pass':
   832:             return False
   833:         return True
   834:     except:
   835:         return True
   836: 
   837: def passed():
   838:     return {'passFail': 'pass'}
   839: 
   840: def failBecause(reason):
   841:     return {'passFail': 'fail', 'reason': reason}
   842: 
   843: # -----------------------------------------------------------------------------
   844: # Generic command tests
   845: 
   846: # A generic command test is expected to run and exit successfully.
   847: #
   848: # The expected exit code can be changed via exit_code() as normal, and
   849: # the expected stdout/stderr are stored in <testname>.stdout and
   850: # <testname>.stderr.  The output of the command can be ignored
   851: # altogether by using run_command_ignore_output instead of
   852: # run_command.
   853: 
   854: def run_command( name, way, cmd ):
   855:     return simple_run( name, '', cmd, '' )
   856: 
   857: # -----------------------------------------------------------------------------
   858: # GHCi tests
   859: 
   860: def ghci_script( name, way, script ):
   861:     # filter out -fforce-recomp from compiler_always_flags, because we're
   862:     # actually testing the recompilation behaviour in the GHCi tests.
   863:     flags = filter(lambda f: f != '-fforce-recomp', getTestOpts().compiler_always_flags)
   864:     flags.append(getTestOpts().extra_hc_opts)
   865: 
   866:     # We pass HC and HC_OPTS as environment variables, so that the
   867:     # script can invoke the correct compiler by using ':! $HC $HC_OPTS'
   868:     cmd = "HC='" + config.compiler + "' " + \
   869:           "HC_OPTS='" + join(flags,' ') + "' " + \
   870:           "'" + config.compiler + "'" + \
   871:           ' --interactive -v0 -ignore-dot-ghci ' + \
   872:           join(flags,' ')
   873: 
   874:     getTestOpts().stdin = script
   875:     return simple_run( name, way, cmd, getTestOpts().extra_run_opts )
   876: 
   877: # -----------------------------------------------------------------------------
   878: # Compile-only tests
   879: 
   880: def compile( name, way, extra_hc_opts ):
   881:     return do_compile( name, way, 0, '', [], extra_hc_opts )
   882: 
   883: def compile_fail( name, way, extra_hc_opts ):
   884:     return do_compile( name, way, 1, '', [], extra_hc_opts )
   885: 
   886: def multimod_compile( name, way, top_mod, extra_hc_opts ):
   887:     return do_compile( name, way, 0, top_mod, [], extra_hc_opts )
   888: 
   889: def multimod_compile_fail( name, way, top_mod, extra_hc_opts ):
   890:     return do_compile( name, way, 1, top_mod, [], extra_hc_opts )
   891: 
   892: def multi_compile( name, way, top_mod, extra_mods, extra_hc_opts ):
   893:     return do_compile( name, way, 0, top_mod, extra_mods, extra_hc_opts)
   894: 
   895: def multi_compile_fail( name, way, top_mod, extra_mods, extra_hc_opts ):
   896:     return do_compile( name, way, 1, top_mod, extra_mods, extra_hc_opts)
   897: 
   898: def do_compile( name, way, should_fail, top_mod, extra_mods, extra_hc_opts ):
   899:     # print 'Compile only, extra args = ', extra_hc_opts
   900:     pretest_cleanup(name)
   901: 
   902:     result = extras_build( way, extra_mods, extra_hc_opts )
   903:     if badResult(result):
   904:        return result
   905:     extra_hc_opts = result['hc_opts']
   906: 
   907:     force = 0
   908:     if extra_mods:
   909:        force = 1
   910:     result = simple_build( name, way, extra_hc_opts, should_fail, top_mod, 0, 1, force)
   911: 
   912:     if badResult(result):
   913:         return result
   914: 
   915:     # the actual stderr should always match the expected, regardless
   916:     # of whether we expected the compilation to fail or not (successful
   917:     # compilations may generate warnings).
   918: 
   919:     if getTestOpts().with_namebase == None:
   920:         namebase = name
   921:     else:
   922:         namebase = getTestOpts().with_namebase
   923: 
   924:     (platform_specific, expected_stderr_file) = platform_wordsize_qualify(namebase, 'stderr', way)
   925:     actual_stderr_file = qualify(name, 'comp.stderr')
   926: 
   927:     if not compare_outputs('stderr', \
   928:                            two_normalisers(two_normalisers(getTestOpts().extra_errmsg_normaliser, normalise_errmsg), normalise_whitespace), \
   929:                            expected_stderr_file, actual_stderr_file):
   930:         return failBecause('stderr mismatch')
   931: 
   932:     # no problems found, this test passed
   933:     return passed()
   934: 
   935: # -----------------------------------------------------------------------------
   936: # Compile-and-run tests
   937: 
   938: def compile_and_run__( name, way, top_mod, extra_mods, extra_hc_opts ):
   939:     # print 'Compile and run, extra args = ', extra_hc_opts
   940:     pretest_cleanup(name)
   941: 
   942:     result = extras_build( way, extra_mods, extra_hc_opts )
   943:     if badResult(result):
   944:        return result
   945:     extra_hc_opts = result['hc_opts']
   946: 
   947:     if way == 'ghci': # interpreted...
   948:         return interpreter_run( name, way, extra_hc_opts, 0, top_mod )
   949:     elif way == 'extcore' or way == 'optextcore' :
   950:         return extcore_run( name, way, extra_hc_opts, 0, top_mod )
   951:     else: # compiled...
   952:         force = 0
   953:         if extra_mods:
   954:            force = 1
   955: 
   956:         result = simple_build( name, way, extra_hc_opts, 0, top_mod, 1, 1, force)
   957:         if badResult(result):
   958:             return result
   959: 
   960:         cmd = './' + name;
   961: 
   962:         # we don't check the compiler's stderr for a compile-and-run test
   963:         return simple_run( name, way, cmd, getTestOpts().extra_run_opts )
   964: 
   965: def compile_and_run( name, way, extra_hc_opts ):
   966:     return compile_and_run__( name, way, '', [], extra_hc_opts)
   967: 
   968: def multimod_compile_and_run( name, way, top_mod, extra_hc_opts ):
   969:     return compile_and_run__( name, way, top_mod, [], extra_hc_opts)
   970: 
   971: def multi_compile_and_run( name, way, top_mod, extra_mods, extra_hc_opts ):
   972:     return compile_and_run__( name, way, top_mod, extra_mods, extra_hc_opts)
   973: 
   974: def stats( name, way, stats_file ):
   975:     opts = getTestOpts()
   976:     return checkStats(stats_file, opts.stats_range_fields
   977:                                 , opts.stats_num_fields)
   978: 
   979: # -----------------------------------------------------------------------------
   980: # Check -t stats info
   981: 
   982: def checkStats(stats_file, range_fields, num_fields):
   983:     result = passed()
   984:     if len(num_fields) + len(range_fields) > 0:
   985:         f = open(in_testdir(stats_file))
   986:         contents = f.read()
   987:         f.close()
   988: 
   989:         for (field, (expected, dev)) in range_fields.items():
   990:             m = re.search('\("' + field + '", "([0-9]+)"\)', contents)
   991:             if m == None:
   992:                 print 'Failed to find field: ', field
   993:                 result = failBecause('no such stats field')
   994:             val = int(m.group(1))
   995: 
   996:             min = expected * ((100 - float(dev))/100);
   997:             max = expected * ((100 + float(dev))/100);
   998: 
   999:             if val < min:
  1000:                 print field, val, 'is more than ' + repr(dev) + '%'
  1001:                 print 'less than the exepected value', expected
  1002:                 print 'If this is because you have improved GHC, please'
  1003:                 print 'update the test so that GHC doesn\'t regress again'
  1004:                 result = failBecause('stat too good')
  1005:             if val > max:
  1006:                 print field, val, 'is more than ' + repr(dev) + '% greater than the expected value,', expected, max
  1007:                 result = failBecause('stat not good enough')
  1008: 
  1009:         # ToDo: remove all uses of this, and delete it
  1010:         for (field, (min, max)) in num_fields.items():
  1011:             m = re.search('\("' + field + '", "([0-9]+)"\)', contents)
  1012:             if m == None:
  1013:                 print 'Failed to find field: ', field
  1014:                 result = failBecause('no such stats field')
  1015:             val = int(m.group(1))
  1016: 
  1017:             if val < min:
  1018:                 print field, val, 'is less than minimum allowed', min
  1019:                 print 'If this is because you have improved GHC, please'
  1020:                 print 'update the test so that GHC doesn\'t regress again'
  1021:                 result = failBecause('stat too good')
  1022:             if val > max:
  1023:                 print field, val, 'is more than maximum allowed', max
  1024:                 result = failBecause('stat not good enough')
  1025: 
  1026:     return result
  1027: 
  1028: # -----------------------------------------------------------------------------
  1029: # Build a single-module program
  1030: 
  1031: def extras_build( way, extra_mods, extra_hc_opts ):
  1032:     for modopts in extra_mods:
  1033:         mod, opts = modopts
  1034:         result = simple_build( mod, way, opts + ' ' + extra_hc_opts, 0, '', 0, 0, 0)
  1035:         if not (mod.endswith('.hs') or mod.endswith('.lhs')):
  1036:             extra_hc_opts += ' ' + replace_suffix(mod, 'o')
  1037:         if badResult(result):
  1038:             return result
  1039: 
  1040:     return {'passFail' : 'pass', 'hc_opts' : extra_hc_opts}
  1041: 
  1042: 
  1043: def simple_build( name, way, extra_hc_opts, should_fail, top_mod, link, addsuf, noforce ):
  1044:     opts = getTestOpts()
  1045:     errname = add_suffix(name, 'comp.stderr')
  1046:     rm_no_fail( qualify(errname, '') )
  1047: 
  1048:     if top_mod != '':
  1049:         srcname = top_mod
  1050:         rm_no_fail( qualify(name, '') )
  1051:         base, suf = os.path.splitext(top_mod)
  1052:         rm_no_fail( qualify(base, '') )
  1053:         rm_no_fail( qualify(base, 'exe') )
  1054:     elif addsuf:
  1055:         srcname = add_hs_lhs_suffix(name)
  1056:         rm_no_fail( qualify(name, '') )
  1057:     else:
  1058:         srcname = name
  1059:         rm_no_fail( qualify(name, 'o') )
  1060: 
  1061:     rm_no_fail( qualify(replace_suffix(srcname, "o"), '') )
  1062: 
  1063:     to_do = ''
  1064:     if top_mod != '':
  1065:         to_do = '--make '
  1066:         if link:
  1067:             to_do = to_do + '-o ' + name
  1068:     elif link:
  1069:         to_do = '-o ' + name
  1070:     elif opts.compile_to_hc:
  1071:         to_do = '-C'
  1072:     else:
  1073:         to_do = '-c' # just compile
  1074: 
  1075:     stats_file = name + '.comp.stats'
  1076:     if len(opts.compiler_stats_num_fields) + len(opts.compiler_stats_range_fields) > 0:
  1077:         extra_hc_opts += ' +RTS -V0 -t' + stats_file + ' --machine-readable -RTS'
  1078: 
  1079:     # Required by GHC 7.3+, harmless for earlier versions:
  1080:     if (getTestOpts().c_src or
  1081:         getTestOpts().objc_src or
  1082:         getTestOpts().objcpp_src):
  1083:         extra_hc_opts += ' -no-hs-main '
  1084: 
  1085:     if getTestOpts().compile_cmd_prefix == '':
  1086:         cmd_prefix = ''
  1087:     else:
  1088:         cmd_prefix = getTestOpts().compile_cmd_prefix + ' '
  1089: 
  1090:     comp_flags = getTestOpts().compiler_always_flags
  1091:     if noforce:
  1092:         comp_flags = filter(lambda f: f != '-fforce-recomp', comp_flags)
  1093: 
  1094:     cmd = 'cd ' + getTestOpts().testdir + " && " + cmd_prefix + "'" \
  1095:           + config.compiler + "' " \
  1096:           + join(comp_flags,' ') + ' ' \
  1097:           + to_do + ' ' + srcname + ' ' \
  1098:           + join(config.way_flags[way],' ') + ' ' \
  1099:           + extra_hc_opts + ' ' \
  1100:           + opts.extra_hc_opts + ' ' \
  1101:           + '>' + errname + ' 2>&1'
  1102: 
  1103:     result = runCmdFor(name, cmd)
  1104: 
  1105:     if result != 0 and not should_fail:
  1106:         actual_stderr = qualify(name, 'comp.stderr')
  1107:         if_verbose(1,'Compile failed (status ' + `result` + ') errors were:')
  1108:         if_verbose_dump(1,actual_stderr)
  1109: 
  1110:     # ToDo: if the sub-shell was killed by ^C, then exit
  1111: 
  1112:     statsResult = checkStats(stats_file, opts.compiler_stats_range_fields
  1113:                                        , opts.compiler_stats_num_fields)
  1114: 
  1115:     if badResult(statsResult):
  1116:         return statsResult
  1117: 
  1118:     if should_fail:
  1119:         if result == 0:
  1120:             return failBecause('exit code 0')
  1121:     else:
  1122:         if result != 0:
  1123:             return failBecause('exit code non-0')
  1124: 
  1125:     return passed()
  1126: 
  1127: # -----------------------------------------------------------------------------
  1128: # Run a program and check its output
  1129: #
  1130: # If testname.stdin exists, route input from that, else
  1131: # from /dev/null.  Route output to testname.run.stdout and
  1132: # testname.run.stderr.  Returns the exit code of the run.
  1133: 
  1134: def simple_run( name, way, prog, args ):
  1135:     opts = getTestOpts()
  1136: 
  1137:     # figure out what to use for stdin
  1138:     if opts.stdin != '':
  1139:         use_stdin = opts.stdin
  1140:     else:
  1141:         stdin_file = add_suffix(name, 'stdin')
  1142:         if os.path.exists(in_testdir(stdin_file)):
  1143:             use_stdin = stdin_file
  1144:         else:
  1145:             use_stdin = '/dev/null'
  1146: 
  1147:     run_stdout = add_suffix(name,'run.stdout')
  1148:     run_stderr = add_suffix(name,'run.stderr')
  1149: 
  1150:     rm_no_fail(qualify(name,'run.stdout'))
  1151:     rm_no_fail(qualify(name,'run.stderr'))
  1152:     rm_no_fail(qualify(name, 'hp'))
  1153:     rm_no_fail(qualify(name,'ps'))
  1154:     rm_no_fail(qualify(name, 'prof'))
  1155: 
  1156:     my_rts_flags = rts_flags(way)
  1157: 
  1158:     stats_file = name + '.stats'
  1159:     if len(opts.stats_range_fields) + len(opts.stats_num_fields) > 0:
  1160:         args += ' +RTS -V0 -t' + stats_file + ' --machine-readable -RTS'
  1161: 
  1162:     if opts.no_stdin:
  1163:         stdin_comes_from = ''
  1164:     else:
  1165:         stdin_comes_from = ' <' + use_stdin
  1166: 
  1167:     if opts.combined_output:
  1168:         redirection = ' >' + run_stdout \
  1169:                     + ' 2>&1'
  1170:     else:
  1171:         redirection = ' >' + run_stdout \
  1172:                     + ' 2>' + run_stderr
  1173: 
  1174:     cmd = prog + ' ' + args + ' '  \
  1175:         + my_rts_flags + ' '       \
  1176:         + stdin_comes_from         \
  1177:         + redirection
  1178: 
  1179:     if getTestOpts().cmd_wrapper != None:
  1180:         cmd = getTestOpts().cmd_wrapper(cmd);
  1181: 
  1182:     cmd = 'cd ' + getTestOpts().testdir + ' && ' + cmd
  1183: 
  1184:     # run the command
  1185:     result = runCmdFor(name, cmd)
  1186: 
  1187:     exit_code = result >> 8
  1188:     signal    = result & 0xff
  1189: 
  1190:     # check the exit code
  1191:     if exit_code != opts.exit_code:
  1192:         print 'Wrong exit code (expected', opts.exit_code, ', actual', exit_code, ')'
  1193:         dump_stdout(name)
  1194:         dump_stderr(name)
  1195:         return failBecause('bad exit code')
  1196: 
  1197:     check_hp = my_rts_flags.find("-h") != -1
  1198:     check_prof = my_rts_flags.find("-p") != -1
  1199: 
  1200:     if not opts.ignore_output:
  1201:         bad_stderr = not opts.combined_output and not check_stderr_ok(name, way)
  1202:         bad_stdout = not check_stdout_ok(name, way)
  1203:         if bad_stderr:
  1204:             return failBecause('bad stderr')
  1205:         if bad_stdout:
  1206:             return failBecause('bad stdout')
  1207:         # exit_code > 127 probably indicates a crash, so don't try to run hp2ps.
  1208:         if check_hp and (exit_code <= 127 or exit_code == 251) and not check_hp_ok(name):
  1209:             return failBecause('bad heap profile')
  1210:         if check_prof and not check_prof_ok(name, way):
  1211:             return failBecause('bad profile')
  1212: 
  1213:     return checkStats(stats_file, opts.stats_range_fields
  1214:                                 , opts.stats_num_fields)
  1215: 
  1216: def rts_flags(way):
  1217:     if (way == ''):
  1218:         return ''
  1219:     else:
  1220:         args = config.way_rts_flags[way]
  1221: 
  1222:     if args == []:
  1223:         return ''
  1224:     else:
  1225:         return '+RTS ' + join(args,' ') + ' -RTS'
  1226: 
  1227: # -----------------------------------------------------------------------------
  1228: # Run a program in the interpreter and check its output
  1229: 
  1230: def interpreter_run( name, way, extra_hc_opts, compile_only, top_mod ):
  1231:     outname = add_suffix(name, 'interp.stdout')
  1232:     errname = add_suffix(name, 'interp.stderr')
  1233:     rm_no_fail(outname)
  1234:     rm_no_fail(errname)
  1235:     rm_no_fail(name)
  1236: 
  1237:     if (top_mod == ''):
  1238:         srcname = add_hs_lhs_suffix(name)
  1239:     else:
  1240:         srcname = top_mod
  1241: 
  1242:     scriptname = add_suffix(name, 'genscript')
  1243:     qscriptname = in_testdir(scriptname)
  1244:     rm_no_fail(qscriptname)
  1245: 
  1246:     delimiter = '===== program output begins here\n'
  1247: 
  1248:     script = open(qscriptname, 'w')
  1249:     if not compile_only:
  1250:         # set the prog name and command-line args to match the compiled
  1251:         # environment.
  1252:         script.write(':set prog ' + name + '\n')
  1253:         script.write(':set args ' + getTestOpts().extra_run_opts + '\n')
  1254:         # Add marker lines to the stdout and stderr output files, so we
  1255:         # can separate GHCi's output from the program's.
  1256:         script.write(':! echo ' + delimiter)
  1257:         script.write(':! echo 1>&2 ' + delimiter)
  1258:         # Set stdout to be line-buffered to match the compiled environment.
  1259:         script.write('System.IO.hSetBuffering System.IO.stdout System.IO.LineBuffering\n')
  1260:         # wrapping in GHC.TopHandler.runIO ensures we get the same output
  1261:         # in the event of an exception as for the compiled program.
  1262:         script.write('GHC.TopHandler.runIOFastExit Main.main Prelude.>> Prelude.return ()\n')
  1263:     script.close()
  1264: 
  1265:     # figure out what to use for stdin
  1266:     if getTestOpts().stdin != '':
  1267:         stdin_file = in_testdir(getTestOpts().stdin)
  1268:     else:
  1269:         stdin_file = qualify(name, 'stdin')
  1270: 
  1271:     if os.path.exists(stdin_file):
  1272:         stdin = open(stdin_file, 'r')
  1273:         os.system('cat ' + stdin_file + ' >>' + qscriptname)
  1274: 
  1275:     script.close()
  1276: 
  1277:     cmd = "'" + config.compiler + "' " \
  1278:           + join(getTestOpts().compiler_always_flags,' ') + ' ' \
  1279:           + srcname + ' ' \
  1280:           + join(config.way_flags[way],' ') + ' ' \
  1281:           + extra_hc_opts + ' ' \
  1282:           + getTestOpts().extra_hc_opts + ' ' \
  1283:           + '<' + scriptname +  ' 1>' + outname + ' 2>' + errname
  1284: 
  1285:     if getTestOpts().cmd_wrapper != None:
  1286:         cmd = getTestOpts().cmd_wrapper(cmd);
  1287: 
  1288:     cmd = 'cd ' + getTestOpts().testdir + " && " + cmd
  1289: 
  1290:     result = runCmdFor(name, cmd)
  1291: 
  1292:     exit_code = result >> 8
  1293:     signal    = result & 0xff
  1294: 
  1295:     # split the stdout into compilation/program output
  1296:     split_file(in_testdir(outname), delimiter,
  1297:                qualify(name, 'comp.stdout'),
  1298:                qualify(name, 'run.stdout'))
  1299:     split_file(in_testdir(errname), delimiter,
  1300:                qualify(name, 'comp.stderr'),
  1301:                qualify(name, 'run.stderr'))
  1302: 
  1303:     # check the exit code
  1304:     if exit_code != getTestOpts().exit_code:
  1305:         print 'Wrong exit code (expected', getTestOpts().exit_code, ', actual', exit_code, ')'
  1306:         dump_stdout(name)
  1307:         dump_stderr(name)
  1308:         return failBecause('bad exit code')
  1309: 
  1310:     # ToDo: if the sub-shell was killed by ^C, then exit
  1311: 
  1312:     if getTestOpts().ignore_output or (check_stderr_ok(name, way) and
  1313:                                        check_stdout_ok(name, way )):
  1314:         return passed()
  1315:     else:
  1316:         return failBecause('bad stdout or stderr')
  1317: 
  1318: 
  1319: def split_file(in_fn, delimiter, out1_fn, out2_fn):
  1320:     infile = open(in_fn)
  1321:     out1 = open(out1_fn, 'w')
  1322:     out2 = open(out2_fn, 'w')
  1323: 
  1324:     line = infile.readline()
  1325:     line = re.sub('\r', '', line) # ignore Windows EOL
  1326:     while (re.sub('^\s*','',line) != delimiter and line != ''):
  1327:         out1.write(line)
  1328:         line = infile.readline()
  1329:         line = re.sub('\r', '', line)
  1330:     out1.close()
  1331: 
  1332:     line = infile.readline()
  1333:     while (line != ''):
  1334:         out2.write(line)
  1335:         line = infile.readline()
  1336:     out2.close()
  1337: 
  1338: # -----------------------------------------------------------------------------
  1339: # Generate External Core for the given program, then compile the resulting Core
  1340: # and compare its output to the expected output
  1341: 
  1342: def extcore_run( name, way, extra_hc_opts, compile_only, top_mod ):
  1343: 
  1344:     depsfilename = qualify(name, 'deps')
  1345:     errname = add_suffix(name, 'comp.stderr')
  1346:     qerrname = qualify(errname,'')
  1347: 
  1348:     hcname = qualify(name, 'hc')
  1349:     oname = qualify(name, 'o')
  1350: 
  1351:     rm_no_fail( qerrname )
  1352:     rm_no_fail( qualify(name, '') )
  1353: 
  1354:     if (top_mod == ''):
  1355:         srcname = add_hs_lhs_suffix(name)
  1356:     else:
  1357:         srcname = top_mod
  1358: 
  1359:     qcorefilename = qualify(name, 'hcr')
  1360:     corefilename = add_suffix(name, 'hcr')
  1361:     rm_no_fail(qcorefilename)
  1362: 
  1363:     # Generate External Core
  1364: 
  1365:     if (top_mod == ''):
  1366:         to_do = ' ' + srcname + ' '
  1367:     else:
  1368:         to_do = ' --make ' + top_mod + ' '
  1369: 
  1370:     cmd = 'cd ' + getTestOpts().testdir + " && '" \
  1371:           + config.compiler + "' " \
  1372:           + join(getTestOpts().compiler_always_flags,' ') + ' ' \
  1373:           + join(config.way_flags[way],' ') + ' ' \
  1374:           + extra_hc_opts + ' ' \
  1375:           + getTestOpts().extra_hc_opts \
  1376:           + to_do \
  1377:           + '>' + errname + ' 2>&1'
  1378:     result = runCmdFor(name, cmd)
  1379: 
  1380:     exit_code = result >> 8
  1381: 
  1382:     if exit_code != 0:
  1383:          if_verbose(1,'Compiling to External Core failed (status ' + `result` + ') errors were:')
  1384:          if_verbose_dump(1,qerrname)
  1385:          return failBecause('ext core exit code non-0')
  1386: 
  1387:      # Compile the resulting files -- if there's more than one module, we need to read the output
  1388:      # of the previous compilation in order to find the dependencies
  1389:     if (top_mod == ''):
  1390:         to_compile = corefilename
  1391:     else:
  1392:         result = runCmdFor(name, 'grep Compiling ' + qerrname + ' |  awk \'{print $4}\' > ' + depsfilename)
  1393:         deps = open(depsfilename).read()
  1394:         deplist = string.replace(deps, '\n',' ');
  1395:         deplist2 = string.replace(deplist,'.lhs,', '.hcr');
  1396:         to_compile = string.replace(deplist2,'.hs,', '.hcr');
  1397: 
  1398:     flags = join(filter(lambda f: f != '-fext-core',config.way_flags[way]),' ')
  1399: 
  1400:     cmd = 'cd ' + getTestOpts().testdir + " && '" \
  1401:           + config.compiler + "' " \
  1402:           + join(getTestOpts().compiler_always_flags,' ') + ' ' \
  1403:           + to_compile + ' ' \
  1404:           + extra_hc_opts + ' ' \
  1405:           + getTestOpts().extra_hc_opts + ' ' \
  1406:           + flags                   \
  1407:           + ' -fglasgow-exts -o ' + name \
  1408:           + '>' + errname + ' 2>&1'
  1409: 
  1410:     result = runCmdFor(name, cmd)
  1411:     exit_code = result >> 8
  1412: 
  1413:     if exit_code != 0:
  1414:         if_verbose(1,'Compiling External Core file(s) failed (status ' + `result` + ') errors were:')
  1415:         if_verbose_dump(1,qerrname)
  1416:         return failBecause('ext core exit code non-0')
  1417: 
  1418:     # Clean up
  1419:     rm_no_fail ( oname )
  1420:     rm_no_fail ( hcname )
  1421:     rm_no_fail ( qcorefilename )
  1422:     rm_no_fail ( depsfilename )
  1423: 
  1424:     return simple_run ( name, way, './'+name, getTestOpts().extra_run_opts )
  1425: 
  1426: # -----------------------------------------------------------------------------
  1427: # Utils
  1428: 
  1429: def check_stdout_ok( name, way ):
  1430:    if getTestOpts().with_namebase == None:
  1431:        namebase = name
  1432:    else:
  1433:        namebase = getTestOpts().with_namebase
  1434: 
  1435:    actual_stdout_file   = qualify(name, 'run.stdout')
  1436:    (platform_specific, expected_stdout_file) = platform_wordsize_qualify(namebase, 'stdout', way)
  1437: 
  1438:    def norm(str):
  1439:       if platform_specific:
  1440:          return str
  1441:       else:
  1442:          return normalise_output(str)
  1443: 
  1444:    return compare_outputs('stdout', \
  1445:                           two_normalisers(norm, getTestOpts().extra_normaliser), \
  1446:                           expected_stdout_file, actual_stdout_file)
  1447: 
  1448: def dump_stdout( name ):
  1449:    print 'Stdout:'
  1450:    print read_no_crs(qualify(name, 'run.stdout'))
  1451: 
  1452: def check_stderr_ok( name, way ):
  1453:    if getTestOpts().with_namebase == None:
  1454:        namebase = name
  1455:    else:
  1456:        namebase = getTestOpts().with_namebase
  1457: 
  1458:    actual_stderr_file   = qualify(name, 'run.stderr')
  1459:    (platform_specific, expected_stderr_file) = platform_wordsize_qualify(namebase, 'stderr', way)
  1460: 
  1461:    def norm(str):
  1462:       if platform_specific:
  1463:          return str
  1464:       else:
  1465:          return normalise_errmsg(str)
  1466: 
  1467:    return compare_outputs('stderr', \
  1468:                           two_normalisers(norm, getTestOpts().extra_normaliser), \
  1469:                           expected_stderr_file, actual_stderr_file)
  1470: 
  1471: def dump_stderr( name ):
  1472:    print "Stderr:"
  1473:    print read_no_crs(qualify(name, 'run.stderr'))
  1474: 
  1475: def read_no_crs(file):
  1476:     str = ''
  1477:     try:
  1478:         h = open(file)
  1479:         str = h.read()
  1480:         h.close
  1481:     except:
  1482:         # On Windows, if the program fails very early, it seems the
  1483:         # files stdout/stderr are redirected to may not get created
  1484:         pass
  1485:     return re.sub('\r', '', str)
  1486: 
  1487: def write_file(file, str):
  1488:     h = open(file, 'w')
  1489:     h.write(str)
  1490:     h.close
  1491: 
  1492: def check_hp_ok(name):
  1493: 
  1494:     # do not qualify for hp2ps because we should be in the right directory
  1495:     hp2psCmd = "cd " + getTestOpts().testdir + " && '" + config.hp2ps + "' " + name
  1496: 
  1497:     hp2psResult = runCmdExitCode(hp2psCmd)
  1498: 
  1499:     actual_ps_file = qualify(name, 'ps')
  1500: 
  1501:     if(hp2psResult == 0):
  1502:         if (os.path.exists(actual_ps_file)):
  1503:             if gs_working:
  1504:                 gsResult = runCmdExitCode(genGSCmd(actual_ps_file))
  1505:                 if (gsResult == 0):
  1506:                     return (True)
  1507:                 else:
  1508:                     print "hp2ps output for " + name + "is not valid PostScript"
  1509:             else: return (True) # assume postscript is valid without ghostscript
  1510:         else:
  1511:             print "hp2ps did not generate PostScript for " + name
  1512:             return (False)
  1513:     else:
  1514:         print "hp2ps error when processing heap profile for " + name
  1515:         return(False)
  1516: 
  1517: def check_prof_ok(name, way):
  1518: 
  1519:     prof_file = qualify(name,'prof')
  1520: 
  1521:     if not os.path.exists(prof_file):
  1522:         print prof_file + " does not exist"
  1523:         return(False)
  1524: 
  1525:     if os.path.getsize(qualify(name,'prof')) == 0:
  1526:         print prof_file + " is empty"
  1527:         return(False)
  1528: 
  1529:     if getTestOpts().with_namebase == None:
  1530:         namebase = name
  1531:     else:
  1532:         namebase = getTestOpts().with_namebase
  1533: 
  1534:     (platform_specific, expected_prof_file) = \
  1535:         platform_wordsize_qualify(namebase, 'prof.sample', way)
  1536: 
  1537:     # sample prof file is not required
  1538:     if not os.path.exists(expected_prof_file):
  1539:         return True
  1540:     else:
  1541:         return compare_outputs('prof', \
  1542:                                two_normalisers(normalise_whitespace,normalise_prof), \
  1543:                                expected_prof_file, prof_file)
  1544: 
  1545: # Compare expected output to actual output, and optionally accept the
  1546: # new output. Returns true if output matched or was accepted, false
  1547: # otherwise.
  1548: def compare_outputs( kind, normaliser, expected_file, actual_file ):
  1549:     if os.path.exists(expected_file):
  1550:         expected_raw = read_no_crs(expected_file)
  1551:         # print "norm:", normaliser(expected_raw)
  1552:         expected_str = normaliser(expected_raw)
  1553:         expected_file_for_diff = expected_file
  1554:     else:
  1555:         expected_str = ''
  1556:         expected_file_for_diff = '/dev/null'
  1557: 
  1558:     actual_raw = read_no_crs(actual_file)
  1559:     actual_str = normaliser(actual_raw)
  1560: 
  1561:     if expected_str == actual_str:
  1562:         return 1
  1563:     else:
  1564:         print 'Actual ' + kind + ' output differs from expected:'
  1565: 
  1566:         if expected_file_for_diff == '/dev/null':
  1567:             expected_normalised_file = '/dev/null'
  1568:         else:
  1569:             expected_normalised_file = expected_file + ".normalised"
  1570:             write_file(expected_normalised_file, expected_str)
  1571: 
  1572:         actual_normalised_file = actual_file + ".normalised"
  1573:         write_file(actual_normalised_file, actual_str)
  1574: 
  1575:         # Ignore whitespace when diffing. We should only get to this
  1576:         # point if there are non-whitespace differences
  1577:         #
  1578:         # Note we are diffing the *actual* output, not the normalised
  1579:         # output.  The normalised output may have whitespace squashed
  1580:         # (including newlines) so the diff would be hard to read.
  1581:         # This does mean that the diff might contain changes that
  1582:         # would be normalised away.
  1583:         r = os.system( 'diff -uw ' + expected_file_for_diff + \
  1584:                                ' ' + actual_file )
  1585: 
  1586:         # If for some reason there were no non-whitespace differences,
  1587:         # then do a full diff
  1588:         if r == 0:
  1589:             r = os.system( 'diff -u ' + expected_file_for_diff + \
  1590:                                   ' ' + actual_file )
  1591: 
  1592:         if config.accept:
  1593:             print 'Accepting new output.'
  1594:             write_file(expected_file, actual_raw)
  1595:             return 1
  1596:         else:
  1597:             return 0
  1598: 
  1599: 
  1600: def normalise_whitespace( str ):
  1601:     # Merge contiguous whitespace characters into a single space.
  1602:     str = re.sub('[ \t\n]+', ' ', str)
  1603:     return str
  1604: 
  1605: def normalise_errmsg( str ):
  1606:     # If somefile ends in ".exe" or ".exe:", zap ".exe" (for Windows)
  1607:     #    the colon is there because it appears in error messages; this
  1608:     #    hacky solution is used in place of more sophisticated filename
  1609:     #    mangling
  1610:     str = re.sub('([^\\s])\\.exe', '\\1', str)
  1611:     # normalise slashes, minimise Windows/Unix filename differences
  1612:     str = re.sub('\\\\', '/', str)
  1613:     # The inplace ghc's are called ghc-stage[123] to avoid filename
  1614:     # collisions, so we need to normalise that to just "ghc"
  1615:     str = re.sub('ghc-stage[123]', 'ghc', str)
  1616:     # We sometimes see the name of the integer-gmp package on stderr,
  1617:     # but this can change (either the implementation name or the
  1618:     # version number), so we canonicalise it here
  1619:     str = re.sub('integer-[a-z]+', 'integer-impl', str)
  1620:     return str
  1621: 
  1622: # normalise a .prof file, so that we can reasonably compare it against
  1623: # a sample.  This doesn't compare any of the actual profiling data,
  1624: # only the shape of the profile and the number of entries.
  1625: def normalise_prof (str):
  1626:     # strip everything up to the line beginning "COST CENTRE"
  1627:     str = re.sub('^(.*\n)*COST CENTRE[^\n]*\n','',str)
  1628: 
  1629:     # strip results for CAFs, these tend to change unpredictably
  1630:     str = re.sub('[ \t]*(CAF|IDLE).*\n','',str)
  1631: 
  1632:     # XXX Ignore Main.main.  Sometimes this appears under CAF, and
  1633:     # sometimes under MAIN.
  1634:     str = re.sub('[ \t]*main[ \t]+Main.*\n','',str)
  1635: 
  1636:     # We have somthing like this:
  1637: 
  1638:     # MAIN      MAIN                 101      0    0.0    0.0   100.0  100.0
  1639:     # k         Main                 204      1    0.0    0.0     0.0    0.0
  1640:     #  foo      Main                 205      1    0.0    0.0     0.0    0.0
  1641:     #   foo.bar Main                 207      1    0.0    0.0     0.0    0.0
  1642: 
  1643:     # then we remove all the specific profiling data, leaving only the
  1644:     # cost centre name, module, and entries, to end up with this:
  1645: 
  1646:     # MAIN                MAIN            0
  1647:     #   k                 Main            1
  1648:     #    foo              Main            1
  1649:     #     foo.bar         Main            1
  1650: 
  1651:     str = re.sub('\n([ \t]*[^ \t]+)([ \t]+[^ \t]+)([ \t]+\\d+)([ \t]+\\d+)[ \t]+([\\d\\.]+)[ \t]+([\\d\\.]+)[ \t]+([\\d\\.]+)[ \t]+([\\d\\.]+)','\n\\1 \\2 \\4',str)
  1652:     return str
  1653: 
  1654: def normalise_slashes_( str ):
  1655:     str = re.sub('\\\\', '/', str)
  1656:     return str
  1657: 
  1658: def normalise_exe_( str ):
  1659:     str = re.sub('\.exe', '', str)
  1660:     return str
  1661: 
  1662: def normalise_output( str ):
  1663:     # Remove a .exe extension (for Windows)
  1664:     # This can occur in error messages generated by the program.
  1665:     str = re.sub('([^\\s])\\.exe', '\\1', str)
  1666:     return str
  1667: 
  1668: def if_verbose( n, str ):
  1669:     if config.verbose >= n:
  1670:         print str
  1671: 
  1672: def if_verbose_dump( n, f ):
  1673:     if config.verbose >= n:
  1674:         try:
  1675:             print open(f).read()
  1676:         except:
  1677:             print ''
  1678: 
  1679: def rawSystem(cmd_and_args):
  1680:     # We prefer subprocess.call to os.spawnv as the latter
  1681:     # seems to send its arguments through a shell or something
  1682:     # with the Windows (non-cygwin) python. An argument "a b c"
  1683:     # turns into three arguments ["a", "b", "c"].
  1684: 
  1685:     # However, subprocess is new in python 2.4, so fall back to
  1686:     # using spawnv if we don't have it
  1687: 
  1688:     if have_subprocess:
  1689:         return subprocess.call(cmd_and_args)
  1690:     else:
  1691:         return os.spawnv(os.P_WAIT, cmd_and_args[0], cmd_and_args)
  1692: 
  1693: # cmd is a complex command in Bourne-shell syntax
  1694: # e.g (cd . && 'c:/users/simonpj/darcs/HEAD/compiler/stage1/ghc-inplace' ...etc)
  1695: # Hence it must ultimately be run by a Bourne shell
  1696: #
  1697: # Mostly it invokes the command wrapped in 'timeout' thus
  1698: #  timeout 300 'cd . && ...blah blah'
  1699: # so it's timeout's job to invoke the Bourne shell
  1700: #
  1701: # But watch out for the case when there is no timeout program!
  1702: # Then, when using the native Python, os.system will invoke the cmd shell
  1703: 
  1704: def runCmd( cmd ):
  1705:     if_verbose( 1, cmd )
  1706:     r = 0
  1707:     if config.os == 'mingw32':
  1708:         # On MinGW, we will always have timeout
  1709:         assert config.timeout_prog!=''
  1710: 
  1711:     if config.timeout_prog != '':
  1712:         r = rawSystem([config.timeout_prog, str(config.timeout), cmd])
  1713:     else:
  1714:         r = os.system(cmd)
  1715:     return r << 8
  1716: 
  1717: def runCmdFor( name, cmd ):
  1718:     if_verbose( 1, cmd )
  1719:     r = 0
  1720:     if config.os == 'mingw32':
  1721:         # On MinGW, we will always have timeout
  1722:         assert config.timeout_prog!=''
  1723: 
  1724:     if config.timeout_prog != '':
  1725:         if config.check_files_written:
  1726:             fn = name + ".strace"
  1727:             r = rawSystem(["strace", "-o", fn, "-fF", "-e", "creat,open,chdir,clone,vfork",
  1728:                            config.timeout_prog, str(config.timeout),
  1729:                            cmd])
  1730:             addTestFilesWritten(name, fn)
  1731:             rm_no_fail(fn)
  1732:         else:
  1733:             r = rawSystem([config.timeout_prog, str(config.timeout), cmd])
  1734:     else:
  1735:         r = os.system(cmd)
  1736:     return r << 8
  1737: 
  1738: def runCmdExitCode( cmd ):
  1739:     return (runCmd(cmd) >> 8);
  1740: 
  1741: 
  1742: # -----------------------------------------------------------------------------
  1743: # checking for files being written to by multiple tests
  1744: 
  1745: re_strace_call_end = '(\) += ([0-9]+|-1 E.*)| <unfinished ...>)$'
  1746: re_strace_unavailable       = re.compile('^\) += \? <unavailable>$')
  1747: re_strace_pid               = re.compile('^([0-9]+) +(.*)')
  1748: re_strace_clone             = re.compile('^(clone\(|<... clone resumed> ).*\) = ([0-9]+)$')
  1749: re_strace_clone_unfinished  = re.compile('^clone\( <unfinished \.\.\.>$')
  1750: re_strace_vfork             = re.compile('^(vfork\(\)|<\.\.\. vfork resumed> \)) += ([0-9]+)$')
  1751: re_strace_vfork_unfinished  = re.compile('^vfork\( <unfinished \.\.\.>$')
  1752: re_strace_chdir             = re.compile('^chdir\("([^"]*)"(\) += 0| <unfinished ...>)$')
  1753: re_strace_chdir_resumed     = re.compile('^<\.\.\. chdir resumed> \) += 0$')
  1754: re_strace_open              = re.compile('^open\("([^"]*)", ([A-Z_|]*)(, [0-9]+)?' + re_strace_call_end)
  1755: re_strace_open_resumed      = re.compile('^<... open resumed> '                    + re_strace_call_end)
  1756: re_strace_ignore_sigchild   = re.compile('^--- SIGCHLD \(Child exited\) @ 0 \(0\) ---$')
  1757: re_strace_ignore_sigvtalarm = re.compile('^--- SIGVTALRM \(Virtual timer expired\) @ 0 \(0\) ---$')
  1758: re_strace_ignore_sigint     = re.compile('^--- SIGINT \(Interrupt\) @ 0 \(0\) ---$')
  1759: re_strace_ignore_sigfpe     = re.compile('^--- SIGFPE \(Floating point exception\) @ 0 \(0\) ---$')
  1760: re_strace_ignore_sigsegv    = re.compile('^--- SIGSEGV \(Segmentation fault\) @ 0 \(0\) ---$')
  1761: re_strace_ignore_sigpipe    = re.compile('^--- SIGPIPE \(Broken pipe\) @ 0 \(0\) ---$')
  1762: 
  1763: # Files that are read or written but shouldn't be:
  1764: # * ghci_history shouldn't be read or written by tests
  1765: # * things under package.conf.d shouldn't be written by tests
  1766: bad_file_usages = {}
  1767: 
  1768: # Mapping from tests to the list of files that they write
  1769: files_written = {}
  1770: 
  1771: # Mapping from tests to the list of files that they write but don't clean
  1772: files_written_not_removed = {}
  1773: 
  1774: def add_bad_file_usage(name, file):
  1775:     try:
  1776:         if not file in bad_file_usages[name]:
  1777:             bad_file_usages[name].append(file)
  1778:     except:
  1779:         bad_file_usages[name] = [file]
  1780: 
  1781: def mkPath(curdir, path):
  1782:     # Given the current full directory is 'curdir', what is the full
  1783:     # path to 'path'?
  1784:     return os.path.realpath(os.path.join(curdir, path))
  1785: 
  1786: def addTestFilesWritten(name, fn):
  1787:     if config.use_threads:
  1788:         with t.lockFilesWritten:
  1789:             addTestFilesWrittenHelper(name, fn)
  1790:     else:
  1791:         addTestFilesWrittenHelper(name, fn)
  1792: 
  1793: def addTestFilesWrittenHelper(name, fn):
  1794:     started = False
  1795:     working_directories = {}
  1796: 
  1797:     with open(fn, 'r') as f:
  1798:         for line in f:
  1799:             m_pid = re_strace_pid.match(line)
  1800:             if m_pid:
  1801:                 pid = m_pid.group(1)
  1802:                 content = m_pid.group(2)
  1803:             elif re_strace_unavailable.match(line):
  1804:                 next
  1805:             else:
  1806:                 framework_fail(name, 'strace', "Can't find pid in strace line: " + line)
  1807: 
  1808:             m_open = re_strace_open.match(content)
  1809:             m_chdir = re_strace_chdir.match(content)
  1810:             m_clone = re_strace_clone.match(content)
  1811:             m_vfork = re_strace_vfork.match(content)
  1812: 
  1813:             if not started:
  1814:                 working_directories[pid] = os.getcwd()
  1815:                 started = True
  1816: 
  1817:             if m_open:
  1818:                 file = m_open.group(1)
  1819:                 file = mkPath(working_directories[pid], file)
  1820:                 if file.endswith("ghci_history"):
  1821:                     add_bad_file_usage(name, file)
  1822:                 elif not file in ['/dev/tty', '/dev/null'] and not file.startswith("/tmp/ghc"):
  1823:                     flags = m_open.group(2).split('|')
  1824:                     if 'O_WRONLY' in flags or 'O_RDWR' in flags:
  1825:                         if re.match('package\.conf\.d', file):
  1826:                             add_bad_file_usage(name, file)
  1827:                         else:
  1828:                             try:
  1829:                                 if not file in files_written[name]:
  1830:                                     files_written[name].append(file)
  1831:                             except:
  1832:                                 files_written[name] = [file]
  1833:                     elif 'O_RDONLY' in flags:
  1834:                         pass
  1835:                     else:
  1836:                         framework_fail(name, 'strace', "Can't understand flags in open strace line: " + line)
  1837:             elif m_chdir:
  1838:                 # We optimistically assume that unfinished chdir's are going to succeed
  1839:                 dir = m_chdir.group(1)
  1840:                 working_directories[pid] = mkPath(working_directories[pid], dir)
  1841:             elif m_clone:
  1842:                 working_directories[m_clone.group(2)] = working_directories[pid]
  1843:             elif m_vfork:
  1844:                 working_directories[m_vfork.group(2)] = working_directories[pid]
  1845:             elif re_strace_open_resumed.match(content):
  1846:                 pass
  1847:             elif re_strace_chdir_resumed.match(content):
  1848:                 pass
  1849:             elif re_strace_vfork_unfinished.match(content):
  1850:                 pass
  1851:             elif re_strace_clone_unfinished.match(content):
  1852:                 pass
  1853:             elif re_strace_ignore_sigchild.match(content):
  1854:                 pass
  1855:             elif re_strace_ignore_sigvtalarm.match(content):
  1856:                 pass
  1857:             elif re_strace_ignore_sigint.match(content):
  1858:                 pass
  1859:             elif re_strace_ignore_sigfpe.match(content):
  1860:                 pass
  1861:             elif re_strace_ignore_sigsegv.match(content):
  1862:                 pass
  1863:             elif re_strace_ignore_sigpipe.match(content):
  1864:                 pass
  1865:             else:
  1866:                 framework_fail(name, 'strace', "Can't understand strace line: " + line)
  1867:  
  1868: def checkForFilesWrittenProblems(file):
  1869:     foundProblem = False
  1870: 
  1871:     files_written_inverted = {}
  1872:     for t in files_written.keys():
  1873:         for f in files_written[t]:
  1874:             try:
  1875:                 files_written_inverted[f].append(t)
  1876:             except:
  1877:                 files_written_inverted[f] = [t]
  1878: 
  1879:     for f in files_written_inverted.keys():
  1880:         if len(files_written_inverted[f]) > 1:
  1881:             if not foundProblem:
  1882:                 foundProblem = True
  1883:                 file.write("\n")
  1884:                 file.write("\nSome files are written by multiple tests:\n")
  1885:             file.write("    " + f + " (" + str(files_written_inverted[f]) + ")\n")
  1886:     if foundProblem:
  1887:         file.write("\n")
  1888: 
  1889:     # -----
  1890: 
  1891:     if len(files_written_not_removed) > 0:
  1892:         file.write("\n")
  1893:         file.write("\nSome files written but not removed:\n")
  1894:         tests = files_written_not_removed.keys()
  1895:         tests.sort()
  1896:         for t in tests:
  1897:             for f in files_written_not_removed[t]:
  1898:                 file.write("    " + t + ": " + f + "\n")
  1899:         file.write("\n")
  1900: 
  1901:     # -----
  1902: 
  1903:     if len(bad_file_usages) > 0:
  1904:         file.write("\n")
  1905:         file.write("\nSome bad file usages:\n")
  1906:         tests = bad_file_usages.keys()
  1907:         tests.sort()
  1908:         for t in tests:
  1909:             for f in bad_file_usages[t]:
  1910:                 file.write("    " + t + ": " + f + "\n")
  1911:         file.write("\n")
  1912: 
  1913: # -----------------------------------------------------------------------------
  1914: # checking if ghostscript is available for checking the output of hp2ps
  1915: 
  1916: def genGSCmd(psfile):
  1917:     return (config.gs + ' -dNODISPLAY -dBATCH -dQUIET -dNOPAUSE ' + psfile);
  1918: 
  1919: def gsNotWorking():
  1920:     global gs_working
  1921:     print "GhostScript not available for hp2ps tests"
  1922: 
  1923: global gs_working
  1924: gs_working = 0
  1925: if config.have_profiling:
  1926:   if config.gs != '':
  1927:     resultGood = runCmdExitCode(genGSCmd(config.confdir + '/good.ps'));
  1928:     if resultGood == 0:
  1929:         resultBad = runCmdExitCode(genGSCmd(config.confdir + '/bad.ps'));
  1930:         if resultBad != 0:
  1931:             print "GhostScript available for hp2ps tests"
  1932:             gs_working = 1;
  1933:         else:
  1934:             gsNotWorking();
  1935:     else:
  1936:         gsNotWorking();
  1937:   else:
  1938:     gsNotWorking();
  1939: 
  1940: def rm_no_fail( file ):
  1941:    try:
  1942:        os.remove( file )
  1943:    finally:
  1944:        return
  1945: 
  1946: def add_suffix( name, suffix ):
  1947:     if suffix == '':
  1948:         return name
  1949:     else:
  1950:         return name + '.' + suffix
  1951: 
  1952: def add_hs_lhs_suffix(name):
  1953:     if getTestOpts().c_src:
  1954:         return add_suffix(name, 'c')
  1955:     elif getTestOpts().objc_src:
  1956:         return add_suffix(name, 'm')
  1957:     elif getTestOpts().objcpp_src:
  1958:         return add_suffix(name, 'mm')
  1959:     elif getTestOpts().literate:
  1960:         return add_suffix(name, 'lhs')
  1961:     else:
  1962:         return add_suffix(name, 'hs')
  1963: 
  1964: def replace_suffix( name, suffix ):
  1965:     base, suf = os.path.splitext(name)
  1966:     return base + '.' + suffix
  1967: 
  1968: def in_testdir( name ):
  1969:     return (getTestOpts().testdir + '/' + name)
  1970: 
  1971: def qualify( name, suff ):
  1972:     return in_testdir(add_suffix(name, suff))
  1973: 
  1974: 
  1975: # Finding the sample output.  The filename is of the form
  1976: #
  1977: #   <test>.stdout[-<compiler>][-<version>][-ws-<wordsize>][-<platform>]
  1978: #
  1979: # and we pick the most specific version available.  The <version> is
  1980: # the major version of the compiler (e.g. 6.8.2 would be "6.8").  For
  1981: # more fine-grained control use if_compiler_lt().
  1982: #
  1983: def platform_wordsize_qualify( name, suff, way ):
  1984: 
  1985:     basepath = qualify(name, suff)
  1986: 
  1987:     paths = [(platformSpecific, basepath + comp + vers + ws + plat + w)
  1988:              for (platformSpecific, plat) in [(1, '-' + config.platform),
  1989:                                               (1, '-' + config.os),
  1990:                                               (0, '')]
  1991:              for ws   in ['-ws-' + config.wordsize, '']
  1992:              for comp in ['-' + config.compiler_type, '']
  1993:              for vers in ['-' + config.compiler_maj_version, '']
  1994:              for w    in ['-' + way, '']]
  1995: 
  1996:     dir = glob.glob(basepath + '*')
  1997:     dir = map (lambda d: normalise_slashes_(d), dir)
  1998: 
  1999:     for (platformSpecific, f) in paths:
  2000:        if f in dir:
  2001:             return (platformSpecific,f)
  2002: 
  2003:     return (0, basepath)
  2004: 
  2005: # Clean up prior to the test, so that we can't spuriously conclude
  2006: # that it passed on the basis of old run outputs.
  2007: def pretest_cleanup(name):
  2008:    rm_no_fail(qualify(name,'comp.stderr'))
  2009:    rm_no_fail(qualify(name,'run.stderr'))
  2010:    rm_no_fail(qualify(name,'run.stdout'))
  2011:    rm_no_fail(qualify(name,'tix'))  # remove the old tix file
  2012:    # simple_build zaps the following:
  2013:    # rm_nofail(qualify("o"))
  2014:    # rm_nofail(qualify(""))
  2015:    # not interested in the return code
  2016: 
  2017: # -----------------------------------------------------------------------------
  2018: # Return a list of all the files ending in '.T' below the directory dir.
  2019: 
  2020: def findTFiles(roots):
  2021:     return concat(map(findTFiles_,roots))
  2022: 
  2023: def findTFiles_(path):
  2024:     if os.path.isdir(path):
  2025:         paths = map(lambda x, p=path: p + '/' + x, os.listdir(path))
  2026:         return findTFiles(paths)
  2027:     elif path[-2:] == '.T':
  2028:         return [path]
  2029:     else:
  2030:         return []
  2031: 
  2032: # -----------------------------------------------------------------------------
  2033: # Output a test summary to the specified file object
  2034: 
  2035: def summary(t, file):
  2036: 
  2037:     file.write('\n')
  2038:     file.write('OVERALL SUMMARY for test run started at ' \
  2039:                + t.start_time + '\n'\
  2040:                + string.rjust(`t.total_tests`, 8) \
  2041:                + ' total tests, which gave rise to\n' \
  2042:                + string.rjust(`t.total_test_cases`, 8) \
  2043:                + ' test cases, of which\n' \
  2044:                + string.rjust(`t.n_framework_failures`, 8) \
  2045:                + ' caused framework failures\n' \
  2046:                + string.rjust(`t.n_tests_skipped`, 8)
  2047:                + ' were skipped\n\n' \
  2048:                + string.rjust(`t.n_expected_passes`, 8)
  2049:                + ' expected passes\n' \
  2050:                + string.rjust(`t.n_missing_libs`, 8)
  2051:                + ' had missing libraries\n' \
  2052:                + string.rjust(`t.n_expected_failures`, 8) \
  2053:                + ' expected failures\n' \
  2054:                + string.rjust(`t.n_unexpected_passes`, 8) \
  2055:                + ' unexpected passes\n'
  2056:                + string.rjust(`t.n_unexpected_failures`, 8) \
  2057:                + ' unexpected failures\n'
  2058:                + '\n')
  2059: 
  2060:     if t.n_unexpected_passes > 0:
  2061:         file.write('Unexpected passes:\n')
  2062:         printPassingTestInfosSummary(file, t.unexpected_passes)
  2063: 
  2064:     if t.n_unexpected_failures > 0:
  2065:         file.write('Unexpected failures:\n')
  2066:         printFailingTestInfosSummary(file, t.unexpected_failures)
  2067: 
  2068:     if config.check_files_written:
  2069:         checkForFilesWrittenProblems(file)
  2070: 
  2071: def printPassingTestInfosSummary(file, testInfos):
  2072:     directories = testInfos.keys()
  2073:     directories.sort()
  2074:     maxDirLen = max(map ((lambda x : len(x)), directories))
  2075:     for directory in directories:
  2076:         tests = testInfos[directory].keys()
  2077:         tests.sort()
  2078:         for test in tests:
  2079:            file.write('   ' + directory.ljust(maxDirLen + 2) + test + \
  2080:                       ' (' + join(testInfos[directory][test],',') + ')\n')
  2081:     file.write('\n')
  2082: 
  2083: def printFailingTestInfosSummary(file, testInfos):
  2084:     directories = testInfos.keys()
  2085:     directories.sort()
  2086:     maxDirLen = max(map ((lambda x : len(x)), directories))
  2087:     for directory in directories:
  2088:         tests = testInfos[directory].keys()
  2089:         tests.sort()
  2090:         for test in tests:
  2091:            reasons = testInfos[directory][test].keys()
  2092:            for reason in reasons:
  2093:                file.write('   ' + directory.ljust(maxDirLen + 2) + test + \
  2094:                           ' [' + reason + ']' + \
  2095:                           ' (' + join(testInfos[directory][test][reason],',') + ')\n')
  2096:     file.write('\n')
  2097: 
  2098: def getStdout(cmd):
  2099:     if have_subprocess:
  2100:         p = subprocess.Popen(cmd,
  2101:                              stdout=subprocess.PIPE,
  2102:                              stderr=subprocess.PIPE)
  2103:         (stdout, stderr) = p.communicate()
  2104:         r = p.wait()
  2105:         if r != 0:
  2106:             raise Exception("Command failed: " + str(cmd))
  2107:         if stderr != '':
  2108:             raise Exception("stderr from command: " + str(cmd))
  2109:         return stdout
  2110:     else:
  2111:         raise Exception("Need subprocess to get stdout, but don't have it")
  2112: 

Generated by git2html.