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