Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | #! /usr/bin/env python |
2 | ||
3 | """Regression test. | |
4 | ||
5 | This will find all modules whose name is "test_*" in the test | |
6 | directory, and run them. Various command line options provide | |
7 | additional facilities. | |
8 | ||
9 | Command line options: | |
10 | ||
11 | -v: verbose -- run tests in verbose mode with output to stdout | |
12 | -q: quiet -- don't print anything except if a test fails | |
13 | -g: generate -- write the output file for a test instead of comparing it | |
14 | -x: exclude -- arguments are tests to *exclude* | |
15 | -s: single -- run only a single test (see below) | |
16 | -r: random -- randomize test execution order | |
17 | -f: fromfile -- read names of tests to run from a file (see below) | |
18 | -l: findleaks -- if GC is available detect tests that leak memory | |
19 | -u: use -- specify which special resource intensive tests to run | |
20 | -h: help -- print this text and exit | |
21 | -t: threshold -- call gc.set_threshold(N) | |
22 | -T: coverage -- turn on code coverage using the trace module | |
23 | -D: coverdir -- Directory where coverage files are put | |
24 | -N: nocoverdir -- Put coverage files alongside modules | |
25 | -L: runleaks -- run the leaks(1) command just before exit | |
26 | -R: huntrleaks -- search for reference leaks (needs debug build, v. slow) | |
27 | ||
28 | If non-option arguments are present, they are names for tests to run, | |
29 | unless -x is given, in which case they are names for tests not to run. | |
30 | If no test names are given, all tests are run. | |
31 | ||
32 | -v is incompatible with -g and does not compare test output files. | |
33 | ||
34 | -T turns on code coverage tracing with the trace module. | |
35 | ||
36 | -D specifies the directory where coverage files are put. | |
37 | ||
38 | -N Put coverage files alongside modules. | |
39 | ||
40 | -s means to run only a single test and exit. This is useful when | |
41 | doing memory analysis on the Python interpreter (which tend to consume | |
42 | too many resources to run the full regression test non-stop). The | |
43 | file /tmp/pynexttest is read to find the next test to run. If this | |
44 | file is missing, the first test_*.py file in testdir or on the command | |
45 | line is used. (actually tempfile.gettempdir() is used instead of | |
46 | /tmp). | |
47 | ||
48 | -f reads the names of tests from the file given as f's argument, one | |
49 | or more test names per line. Whitespace is ignored. Blank lines and | |
50 | lines beginning with '#' are ignored. This is especially useful for | |
51 | whittling down failures involving interactions among tests. | |
52 | ||
53 | -L causes the leaks(1) command to be run just before exit if it exists. | |
54 | leaks(1) is available on Mac OS X and presumably on some other | |
55 | FreeBSD-derived systems. | |
56 | ||
57 | -R runs each test several times and examines sys.gettotalrefcount() to | |
58 | see if the test appears to be leaking references. The argument should | |
59 | be of the form stab:run:fname where 'stab' is the number of times the | |
60 | test is run to let gettotalrefcount settle down, 'run' is the number | |
61 | of times further it is run and 'fname' is the name of the file the | |
62 | reports are written to. These parameters all have defaults (5, 4 and | |
63 | "reflog.txt" respectively), so the minimal invocation is '-R ::'. | |
64 | ||
65 | -u is used to specify which special resource intensive tests to run, | |
66 | such as those requiring large file support or network connectivity. | |
67 | The argument is a comma-separated list of words indicating the | |
68 | resources to test. Currently only the following are defined: | |
69 | ||
70 | all - Enable all special resources. | |
71 | ||
72 | audio - Tests that use the audio device. (There are known | |
73 | cases of broken audio drivers that can crash Python or | |
74 | even the Linux kernel.) | |
75 | ||
76 | curses - Tests that use curses and will modify the terminal's | |
77 | state and output modes. | |
78 | ||
79 | largefile - It is okay to run some test that may create huge | |
80 | files. These tests can take a long time and may | |
81 | consume >2GB of disk space temporarily. | |
82 | ||
83 | network - It is okay to run tests that use external network | |
84 | resource, e.g. testing SSL support for sockets. | |
85 | ||
86 | bsddb - It is okay to run the bsddb testsuite, which takes | |
87 | a long time to complete. | |
88 | ||
89 | decimal - Test the decimal module against a large suite that | |
90 | verifies compliance with standards. | |
91 | ||
92 | compiler - Test the compiler package by compiling all the source | |
93 | in the standard library and test suite. This takes | |
94 | a long time. | |
95 | ||
96 | subprocess Run all tests for the subprocess module. | |
97 | ||
98 | To enable all resources except one, use '-uall,-<resource>'. For | |
99 | example, to run all the tests except for the bsddb tests, give the | |
100 | option '-uall,-bsddb'. | |
101 | """ | |
102 | ||
103 | import os | |
104 | import sys | |
105 | import getopt | |
106 | import random | |
107 | import warnings | |
108 | import sre | |
109 | import cStringIO | |
110 | import traceback | |
111 | ||
112 | # I see no other way to suppress these warnings; | |
113 | # putting them in test_grammar.py has no effect: | |
114 | warnings.filterwarnings("ignore", "hex/oct constants", FutureWarning, | |
115 | ".*test.test_grammar$") | |
116 | if sys.maxint > 0x7fffffff: | |
117 | # Also suppress them in <string>, because for 64-bit platforms, | |
118 | # that's where test_grammar.py hides them. | |
119 | warnings.filterwarnings("ignore", "hex/oct constants", FutureWarning, | |
120 | "<string>") | |
121 | ||
122 | # MacOSX (a.k.a. Darwin) has a default stack size that is too small | |
123 | # for deeply recursive regular expressions. We see this as crashes in | |
124 | # the Python test suite when running test_re.py and test_sre.py. The | |
125 | # fix is to set the stack limit to 2048. | |
126 | # This approach may also be useful for other Unixy platforms that | |
127 | # suffer from small default stack limits. | |
128 | if sys.platform == 'darwin': | |
129 | try: | |
130 | import resource | |
131 | except ImportError: | |
132 | pass | |
133 | else: | |
134 | soft, hard = resource.getrlimit(resource.RLIMIT_STACK) | |
135 | newsoft = min(hard, max(soft, 1024*2048)) | |
136 | resource.setrlimit(resource.RLIMIT_STACK, (newsoft, hard)) | |
137 | ||
138 | from test import test_support | |
139 | ||
140 | RESOURCE_NAMES = ('audio', 'curses', 'largefile', 'network', 'bsddb', | |
141 | 'decimal', 'compiler', 'subprocess') | |
142 | ||
143 | ||
144 | def usage(code, msg=''): | |
145 | print __doc__ | |
146 | if msg: print msg | |
147 | sys.exit(code) | |
148 | ||
149 | ||
150 | def main(tests=None, testdir=None, verbose=0, quiet=False, generate=False, | |
151 | exclude=False, single=False, randomize=False, fromfile=None, | |
152 | findleaks=False, use_resources=None, trace=False, coverdir='coverage', | |
153 | runleaks=False, huntrleaks=False): | |
154 | """Execute a test suite. | |
155 | ||
156 | This also parses command-line options and modifies its behavior | |
157 | accordingly. | |
158 | ||
159 | tests -- a list of strings containing test names (optional) | |
160 | testdir -- the directory in which to look for tests (optional) | |
161 | ||
162 | Users other than the Python test suite will certainly want to | |
163 | specify testdir; if it's omitted, the directory containing the | |
164 | Python test suite is searched for. | |
165 | ||
166 | If the tests argument is omitted, the tests listed on the | |
167 | command-line will be used. If that's empty, too, then all *.py | |
168 | files beginning with test_ will be used. | |
169 | ||
170 | The other default arguments (verbose, quiet, generate, exclude, single, | |
171 | randomize, findleaks, use_resources, trace and coverdir) allow programmers | |
172 | calling main() directly to set the values that would normally be set by | |
173 | flags on the command line. | |
174 | """ | |
175 | ||
176 | test_support.record_original_stdout(sys.stdout) | |
177 | try: | |
178 | opts, args = getopt.getopt(sys.argv[1:], 'hvgqxsrf:lu:t:TD:NLR:', | |
179 | ['help', 'verbose', 'quiet', 'generate', | |
180 | 'exclude', 'single', 'random', 'fromfile', | |
181 | 'findleaks', 'use=', 'threshold=', 'trace', | |
182 | 'coverdir=', 'nocoverdir', 'runleaks', | |
183 | 'huntrleaks=' | |
184 | ]) | |
185 | except getopt.error, msg: | |
186 | usage(2, msg) | |
187 | ||
188 | # Defaults | |
189 | if use_resources is None: | |
190 | use_resources = [] | |
191 | for o, a in opts: | |
192 | if o in ('-h', '--help'): | |
193 | usage(0) | |
194 | elif o in ('-v', '--verbose'): | |
195 | verbose += 1 | |
196 | elif o in ('-q', '--quiet'): | |
197 | quiet = True; | |
198 | verbose = 0 | |
199 | elif o in ('-g', '--generate'): | |
200 | generate = True | |
201 | elif o in ('-x', '--exclude'): | |
202 | exclude = True | |
203 | elif o in ('-s', '--single'): | |
204 | single = True | |
205 | elif o in ('-r', '--randomize'): | |
206 | randomize = True | |
207 | elif o in ('-f', '--fromfile'): | |
208 | fromfile = a | |
209 | elif o in ('-l', '--findleaks'): | |
210 | findleaks = True | |
211 | elif o in ('-L', '--runleaks'): | |
212 | runleaks = True | |
213 | elif o in ('-t', '--threshold'): | |
214 | import gc | |
215 | gc.set_threshold(int(a)) | |
216 | elif o in ('-T', '--coverage'): | |
217 | trace = True | |
218 | elif o in ('-D', '--coverdir'): | |
219 | coverdir = os.path.join(os.getcwd(), a) | |
220 | elif o in ('-N', '--nocoverdir'): | |
221 | coverdir = None | |
222 | elif o in ('-R', '--huntrleaks'): | |
223 | huntrleaks = a.split(':') | |
224 | if len(huntrleaks) != 3: | |
225 | print a, huntrleaks | |
226 | usage(2, '-R takes three colon-separated arguments') | |
227 | if len(huntrleaks[0]) == 0: | |
228 | huntrleaks[0] = 5 | |
229 | else: | |
230 | huntrleaks[0] = int(huntrleaks[0]) | |
231 | if len(huntrleaks[1]) == 0: | |
232 | huntrleaks[1] = 4 | |
233 | else: | |
234 | huntrleaks[1] = int(huntrleaks[1]) | |
235 | if len(huntrleaks[2]) == 0: | |
236 | huntrleaks[2] = "reflog.txt" | |
237 | elif o in ('-u', '--use'): | |
238 | u = [x.lower() for x in a.split(',')] | |
239 | for r in u: | |
240 | if r == 'all': | |
241 | use_resources[:] = RESOURCE_NAMES | |
242 | continue | |
243 | remove = False | |
244 | if r[0] == '-': | |
245 | remove = True | |
246 | r = r[1:] | |
247 | if r not in RESOURCE_NAMES: | |
248 | usage(1, 'Invalid -u/--use option: ' + a) | |
249 | if remove: | |
250 | if r in use_resources: | |
251 | use_resources.remove(r) | |
252 | elif r not in use_resources: | |
253 | use_resources.append(r) | |
254 | if generate and verbose: | |
255 | usage(2, "-g and -v don't go together!") | |
256 | if single and fromfile: | |
257 | usage(2, "-s and -f don't go together!") | |
258 | ||
259 | good = [] | |
260 | bad = [] | |
261 | skipped = [] | |
262 | resource_denieds = [] | |
263 | ||
264 | if findleaks: | |
265 | try: | |
266 | import gc | |
267 | except ImportError: | |
268 | print 'No GC available, disabling findleaks.' | |
269 | findleaks = False | |
270 | else: | |
271 | # Uncomment the line below to report garbage that is not | |
272 | # freeable by reference counting alone. By default only | |
273 | # garbage that is not collectable by the GC is reported. | |
274 | #gc.set_debug(gc.DEBUG_SAVEALL) | |
275 | found_garbage = [] | |
276 | ||
277 | if single: | |
278 | from tempfile import gettempdir | |
279 | filename = os.path.join(gettempdir(), 'pynexttest') | |
280 | try: | |
281 | fp = open(filename, 'r') | |
282 | next = fp.read().strip() | |
283 | tests = [next] | |
284 | fp.close() | |
285 | except IOError: | |
286 | pass | |
287 | ||
288 | if fromfile: | |
289 | tests = [] | |
290 | fp = open(fromfile) | |
291 | for line in fp: | |
292 | guts = line.split() # assuming no test has whitespace in its name | |
293 | if guts and not guts[0].startswith('#'): | |
294 | tests.extend(guts) | |
295 | fp.close() | |
296 | ||
297 | # Strip .py extensions. | |
298 | if args: | |
299 | args = map(removepy, args) | |
300 | if tests: | |
301 | tests = map(removepy, tests) | |
302 | ||
303 | stdtests = STDTESTS[:] | |
304 | nottests = NOTTESTS[:] | |
305 | if exclude: | |
306 | for arg in args: | |
307 | if arg in stdtests: | |
308 | stdtests.remove(arg) | |
309 | nottests[:0] = args | |
310 | args = [] | |
311 | tests = tests or args or findtests(testdir, stdtests, nottests) | |
312 | if single: | |
313 | tests = tests[:1] | |
314 | if randomize: | |
315 | random.shuffle(tests) | |
316 | if trace: | |
317 | import trace | |
318 | tracer = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix], | |
319 | trace=False, count=True) | |
320 | test_support.verbose = verbose # Tell tests to be moderately quiet | |
321 | test_support.use_resources = use_resources | |
322 | save_modules = sys.modules.keys() | |
323 | for test in tests: | |
324 | if not quiet: | |
325 | print test | |
326 | sys.stdout.flush() | |
327 | if trace: | |
328 | # If we're tracing code coverage, then we don't exit with status | |
329 | # if on a false return value from main. | |
330 | tracer.runctx('runtest(test, generate, verbose, quiet, testdir)', | |
331 | globals=globals(), locals=vars()) | |
332 | else: | |
333 | ok = runtest(test, generate, verbose, quiet, testdir, huntrleaks) | |
334 | if ok > 0: | |
335 | good.append(test) | |
336 | elif ok == 0: | |
337 | bad.append(test) | |
338 | else: | |
339 | skipped.append(test) | |
340 | if ok == -2: | |
341 | resource_denieds.append(test) | |
342 | if findleaks: | |
343 | gc.collect() | |
344 | if gc.garbage: | |
345 | print "Warning: test created", len(gc.garbage), | |
346 | print "uncollectable object(s)." | |
347 | # move the uncollectable objects somewhere so we don't see | |
348 | # them again | |
349 | found_garbage.extend(gc.garbage) | |
350 | del gc.garbage[:] | |
351 | # Unload the newly imported modules (best effort finalization) | |
352 | for module in sys.modules.keys(): | |
353 | if module not in save_modules and module.startswith("test."): | |
354 | test_support.unload(module) | |
355 | ||
356 | # The lists won't be sorted if running with -r | |
357 | good.sort() | |
358 | bad.sort() | |
359 | skipped.sort() | |
360 | ||
361 | if good and not quiet: | |
362 | if not bad and not skipped and len(good) > 1: | |
363 | print "All", | |
364 | print count(len(good), "test"), "OK." | |
365 | if verbose: | |
366 | print "CAUTION: stdout isn't compared in verbose mode:" | |
367 | print "a test that passes in verbose mode may fail without it." | |
368 | if bad: | |
369 | print count(len(bad), "test"), "failed:" | |
370 | printlist(bad) | |
371 | if skipped and not quiet: | |
372 | print count(len(skipped), "test"), "skipped:" | |
373 | printlist(skipped) | |
374 | ||
375 | e = _ExpectedSkips() | |
376 | plat = sys.platform | |
377 | if e.isvalid(): | |
378 | surprise = set(skipped) - e.getexpected() - set(resource_denieds) | |
379 | if surprise: | |
380 | print count(len(surprise), "skip"), \ | |
381 | "unexpected on", plat + ":" | |
382 | printlist(surprise) | |
383 | else: | |
384 | print "Those skips are all expected on", plat + "." | |
385 | else: | |
386 | print "Ask someone to teach regrtest.py about which tests are" | |
387 | print "expected to get skipped on", plat + "." | |
388 | ||
389 | if single: | |
390 | alltests = findtests(testdir, stdtests, nottests) | |
391 | for i in range(len(alltests)): | |
392 | if tests[0] == alltests[i]: | |
393 | if i == len(alltests) - 1: | |
394 | os.unlink(filename) | |
395 | else: | |
396 | fp = open(filename, 'w') | |
397 | fp.write(alltests[i+1] + '\n') | |
398 | fp.close() | |
399 | break | |
400 | else: | |
401 | os.unlink(filename) | |
402 | ||
403 | if trace: | |
404 | r = tracer.results() | |
405 | r.write_results(show_missing=True, summary=True, coverdir=coverdir) | |
406 | ||
407 | if runleaks: | |
408 | os.system("leaks %d" % os.getpid()) | |
409 | ||
410 | sys.exit(len(bad) > 0) | |
411 | ||
412 | ||
413 | STDTESTS = [ | |
414 | 'test_grammar', | |
415 | 'test_opcodes', | |
416 | 'test_operations', | |
417 | 'test_builtin', | |
418 | 'test_exceptions', | |
419 | 'test_types', | |
420 | ] | |
421 | ||
422 | NOTTESTS = [ | |
423 | 'test_support', | |
424 | 'test_future1', | |
425 | 'test_future2', | |
426 | 'test_future3', | |
427 | ] | |
428 | ||
429 | def findtests(testdir=None, stdtests=STDTESTS, nottests=NOTTESTS): | |
430 | """Return a list of all applicable test modules.""" | |
431 | if not testdir: testdir = findtestdir() | |
432 | names = os.listdir(testdir) | |
433 | tests = [] | |
434 | for name in names: | |
435 | if name[:5] == "test_" and name[-3:] == os.extsep+"py": | |
436 | modname = name[:-3] | |
437 | if modname not in stdtests and modname not in nottests: | |
438 | tests.append(modname) | |
439 | tests.sort() | |
440 | return stdtests + tests | |
441 | ||
442 | def runtest(test, generate, verbose, quiet, testdir=None, huntrleaks=False): | |
443 | """Run a single test. | |
444 | test -- the name of the test | |
445 | generate -- if true, generate output, instead of running the test | |
446 | and comparing it to a previously created output file | |
447 | verbose -- if true, print more messages | |
448 | quiet -- if true, don't print 'skipped' messages (probably redundant) | |
449 | testdir -- test directory | |
450 | """ | |
451 | test_support.unload(test) | |
452 | if not testdir: | |
453 | testdir = findtestdir() | |
454 | outputdir = os.path.join(testdir, "output") | |
455 | outputfile = os.path.join(outputdir, test) | |
456 | if verbose: | |
457 | cfp = None | |
458 | else: | |
459 | cfp = cStringIO.StringIO() | |
460 | if huntrleaks: | |
461 | refrep = open(huntrleaks[2], "a") | |
462 | try: | |
463 | save_stdout = sys.stdout | |
464 | try: | |
465 | if cfp: | |
466 | sys.stdout = cfp | |
467 | print test # Output file starts with test name | |
468 | if test.startswith('test.'): | |
469 | abstest = test | |
470 | else: | |
471 | # Always import it from the test package | |
472 | abstest = 'test.' + test | |
473 | the_package = __import__(abstest, globals(), locals(), []) | |
474 | the_module = getattr(the_package, test) | |
475 | # Most tests run to completion simply as a side-effect of | |
476 | # being imported. For the benefit of tests that can't run | |
477 | # that way (like test_threaded_import), explicitly invoke | |
478 | # their test_main() function (if it exists). | |
479 | indirect_test = getattr(the_module, "test_main", None) | |
480 | if indirect_test is not None: | |
481 | indirect_test() | |
482 | if huntrleaks: | |
483 | # This code *is* hackish and inelegant, yes. | |
484 | # But it seems to do the job. | |
485 | import copy_reg | |
486 | fs = warnings.filters[:] | |
487 | ps = copy_reg.dispatch_table.copy() | |
488 | pic = sys.path_importer_cache.copy() | |
489 | import gc | |
490 | def cleanup(): | |
491 | import _strptime, urlparse, warnings, dircache | |
492 | from distutils.dir_util import _path_created | |
493 | _path_created.clear() | |
494 | warnings.filters[:] = fs | |
495 | gc.collect() | |
496 | sre.purge() | |
497 | _strptime._regex_cache.clear() | |
498 | urlparse.clear_cache() | |
499 | copy_reg.dispatch_table.clear() | |
500 | copy_reg.dispatch_table.update(ps) | |
501 | sys.path_importer_cache.clear() | |
502 | sys.path_importer_cache.update(pic) | |
503 | dircache.reset() | |
504 | if indirect_test: | |
505 | def run_the_test(): | |
506 | indirect_test() | |
507 | else: | |
508 | def run_the_test(): | |
509 | reload(the_module) | |
510 | deltas = [] | |
511 | repcount = huntrleaks[0] + huntrleaks[1] | |
512 | print >> sys.stderr, "beginning", repcount, "repetitions" | |
513 | print >> sys.stderr, \ | |
514 | ("1234567890"*(repcount//10 + 1))[:repcount] | |
515 | for i in range(repcount): | |
516 | rc = sys.gettotalrefcount() | |
517 | run_the_test() | |
518 | sys.stderr.write('.') | |
519 | cleanup() | |
520 | deltas.append(sys.gettotalrefcount() - rc - 2) | |
521 | print >>sys.stderr | |
522 | if max(map(abs, deltas[-huntrleaks[1]:])) > 0: | |
523 | print >>sys.stderr, test, 'leaked', \ | |
524 | deltas[-huntrleaks[1]:], 'references' | |
525 | print >>refrep, test, 'leaked', \ | |
526 | deltas[-huntrleaks[1]:], 'references' | |
527 | # The end of the huntrleaks hackishness. | |
528 | finally: | |
529 | sys.stdout = save_stdout | |
530 | except test_support.ResourceDenied, msg: | |
531 | if not quiet: | |
532 | print test, "skipped --", msg | |
533 | sys.stdout.flush() | |
534 | return -2 | |
535 | except (ImportError, test_support.TestSkipped), msg: | |
536 | if not quiet: | |
537 | print test, "skipped --", msg | |
538 | sys.stdout.flush() | |
539 | return -1 | |
540 | except KeyboardInterrupt: | |
541 | raise | |
542 | except test_support.TestFailed, msg: | |
543 | print "test", test, "failed --", msg | |
544 | sys.stdout.flush() | |
545 | return 0 | |
546 | except: | |
547 | type, value = sys.exc_info()[:2] | |
548 | print "test", test, "crashed --", str(type) + ":", value | |
549 | sys.stdout.flush() | |
550 | if verbose: | |
551 | traceback.print_exc(file=sys.stdout) | |
552 | sys.stdout.flush() | |
553 | return 0 | |
554 | else: | |
555 | if not cfp: | |
556 | return 1 | |
557 | output = cfp.getvalue() | |
558 | if generate: | |
559 | if output == test + "\n": | |
560 | if os.path.exists(outputfile): | |
561 | # Write it since it already exists (and the contents | |
562 | # may have changed), but let the user know it isn't | |
563 | # needed: | |
564 | print "output file", outputfile, \ | |
565 | "is no longer needed; consider removing it" | |
566 | else: | |
567 | # We don't need it, so don't create it. | |
568 | return 1 | |
569 | fp = open(outputfile, "w") | |
570 | fp.write(output) | |
571 | fp.close() | |
572 | return 1 | |
573 | if os.path.exists(outputfile): | |
574 | fp = open(outputfile, "r") | |
575 | expected = fp.read() | |
576 | fp.close() | |
577 | else: | |
578 | expected = test + "\n" | |
579 | if output == expected or huntrleaks: | |
580 | return 1 | |
581 | print "test", test, "produced unexpected output:" | |
582 | sys.stdout.flush() | |
583 | reportdiff(expected, output) | |
584 | sys.stdout.flush() | |
585 | return 0 | |
586 | ||
587 | def reportdiff(expected, output): | |
588 | import difflib | |
589 | print "*" * 70 | |
590 | a = expected.splitlines(1) | |
591 | b = output.splitlines(1) | |
592 | sm = difflib.SequenceMatcher(a=a, b=b) | |
593 | tuples = sm.get_opcodes() | |
594 | ||
595 | def pair(x0, x1): | |
596 | # x0:x1 are 0-based slice indices; convert to 1-based line indices. | |
597 | x0 += 1 | |
598 | if x0 >= x1: | |
599 | return "line " + str(x0) | |
600 | else: | |
601 | return "lines %d-%d" % (x0, x1) | |
602 | ||
603 | for op, a0, a1, b0, b1 in tuples: | |
604 | if op == 'equal': | |
605 | pass | |
606 | ||
607 | elif op == 'delete': | |
608 | print "***", pair(a0, a1), "of expected output missing:" | |
609 | for line in a[a0:a1]: | |
610 | print "-", line, | |
611 | ||
612 | elif op == 'replace': | |
613 | print "*** mismatch between", pair(a0, a1), "of expected", \ | |
614 | "output and", pair(b0, b1), "of actual output:" | |
615 | for line in difflib.ndiff(a[a0:a1], b[b0:b1]): | |
616 | print line, | |
617 | ||
618 | elif op == 'insert': | |
619 | print "***", pair(b0, b1), "of actual output doesn't appear", \ | |
620 | "in expected output after line", str(a1)+":" | |
621 | for line in b[b0:b1]: | |
622 | print "+", line, | |
623 | ||
624 | else: | |
625 | print "get_opcodes() returned bad tuple?!?!", (op, a0, a1, b0, b1) | |
626 | ||
627 | print "*" * 70 | |
628 | ||
629 | def findtestdir(): | |
630 | if __name__ == '__main__': | |
631 | file = sys.argv[0] | |
632 | else: | |
633 | file = __file__ | |
634 | testdir = os.path.dirname(file) or os.curdir | |
635 | return testdir | |
636 | ||
637 | def removepy(name): | |
638 | if name.endswith(os.extsep + "py"): | |
639 | name = name[:-3] | |
640 | return name | |
641 | ||
642 | def count(n, word): | |
643 | if n == 1: | |
644 | return "%d %s" % (n, word) | |
645 | else: | |
646 | return "%d %ss" % (n, word) | |
647 | ||
648 | def printlist(x, width=70, indent=4): | |
649 | """Print the elements of iterable x to stdout. | |
650 | ||
651 | Optional arg width (default 70) is the maximum line length. | |
652 | Optional arg indent (default 4) is the number of blanks with which to | |
653 | begin each line. | |
654 | """ | |
655 | ||
656 | from textwrap import fill | |
657 | blanks = ' ' * indent | |
658 | print fill(' '.join(map(str, x)), width, | |
659 | initial_indent=blanks, subsequent_indent=blanks) | |
660 | ||
661 | # Map sys.platform to a string containing the basenames of tests | |
662 | # expected to be skipped on that platform. | |
663 | # | |
664 | # Special cases: | |
665 | # test_pep277 | |
666 | # The _ExpectedSkips constructor adds this to the set of expected | |
667 | # skips if not os.path.supports_unicode_filenames. | |
668 | # test_normalization | |
669 | # Whether a skip is expected here depends on whether a large test | |
670 | # input file has been downloaded. test_normalization.skip_expected | |
671 | # controls that. | |
672 | # test_socket_ssl | |
673 | # Controlled by test_socket_ssl.skip_expected. Requires the network | |
674 | # resource, and a socket module with ssl support. | |
675 | # test_timeout | |
676 | # Controlled by test_timeout.skip_expected. Requires the network | |
677 | # resource and a socket module. | |
678 | # test_codecmaps_* | |
679 | # Whether a skip is expected here depends on whether a large test | |
680 | # input file has been downloaded. test_codecmaps_*.skip_expected | |
681 | # controls that. | |
682 | ||
683 | _expectations = { | |
684 | 'win32': | |
685 | """ | |
686 | test__locale | |
687 | test_applesingle | |
688 | test_al | |
689 | test_bsddb185 | |
690 | test_bsddb3 | |
691 | test_cd | |
692 | test_cl | |
693 | test_commands | |
694 | test_crypt | |
695 | test_curses | |
696 | test_dbm | |
697 | test_dl | |
698 | test_fcntl | |
699 | test_fork1 | |
700 | test_gdbm | |
701 | test_gl | |
702 | test_grp | |
703 | test_imgfile | |
704 | test_ioctl | |
705 | test_largefile | |
706 | test_linuxaudiodev | |
707 | test_mhlib | |
708 | test_nis | |
709 | test_openpty | |
710 | test_ossaudiodev | |
711 | test_poll | |
712 | test_posix | |
713 | test_pty | |
714 | test_pwd | |
715 | test_resource | |
716 | test_signal | |
717 | test_sunaudiodev | |
718 | test_threadsignals | |
719 | test_timing | |
720 | """, | |
721 | 'linux2': | |
722 | """ | |
723 | test_al | |
724 | test_applesingle | |
725 | test_bsddb185 | |
726 | test_cd | |
727 | test_cl | |
728 | test_curses | |
729 | test_dl | |
730 | test_gl | |
731 | test_imgfile | |
732 | test_largefile | |
733 | test_linuxaudiodev | |
734 | test_nis | |
735 | test_ntpath | |
736 | test_ossaudiodev | |
737 | test_sunaudiodev | |
738 | """, | |
739 | 'mac': | |
740 | """ | |
741 | test_al | |
742 | test_atexit | |
743 | test_bsddb | |
744 | test_bsddb185 | |
745 | test_bsddb3 | |
746 | test_bz2 | |
747 | test_cd | |
748 | test_cl | |
749 | test_commands | |
750 | test_crypt | |
751 | test_curses | |
752 | test_dbm | |
753 | test_dl | |
754 | test_fcntl | |
755 | test_fork1 | |
756 | test_gl | |
757 | test_grp | |
758 | test_ioctl | |
759 | test_imgfile | |
760 | test_largefile | |
761 | test_linuxaudiodev | |
762 | test_locale | |
763 | test_mmap | |
764 | test_nis | |
765 | test_ntpath | |
766 | test_openpty | |
767 | test_ossaudiodev | |
768 | test_poll | |
769 | test_popen | |
770 | test_popen2 | |
771 | test_posix | |
772 | test_pty | |
773 | test_pwd | |
774 | test_resource | |
775 | test_signal | |
776 | test_sunaudiodev | |
777 | test_sundry | |
778 | test_tarfile | |
779 | test_timing | |
780 | """, | |
781 | 'unixware7': | |
782 | """ | |
783 | test_al | |
784 | test_applesingle | |
785 | test_bsddb | |
786 | test_bsddb185 | |
787 | test_cd | |
788 | test_cl | |
789 | test_dl | |
790 | test_gl | |
791 | test_imgfile | |
792 | test_largefile | |
793 | test_linuxaudiodev | |
794 | test_minidom | |
795 | test_nis | |
796 | test_ntpath | |
797 | test_openpty | |
798 | test_pyexpat | |
799 | test_sax | |
800 | test_sunaudiodev | |
801 | test_sundry | |
802 | """, | |
803 | 'openunix8': | |
804 | """ | |
805 | test_al | |
806 | test_applesingle | |
807 | test_bsddb | |
808 | test_bsddb185 | |
809 | test_cd | |
810 | test_cl | |
811 | test_dl | |
812 | test_gl | |
813 | test_imgfile | |
814 | test_largefile | |
815 | test_linuxaudiodev | |
816 | test_minidom | |
817 | test_nis | |
818 | test_ntpath | |
819 | test_openpty | |
820 | test_pyexpat | |
821 | test_sax | |
822 | test_sunaudiodev | |
823 | test_sundry | |
824 | """, | |
825 | 'sco_sv3': | |
826 | """ | |
827 | test_al | |
828 | test_applesingle | |
829 | test_asynchat | |
830 | test_bsddb | |
831 | test_bsddb185 | |
832 | test_cd | |
833 | test_cl | |
834 | test_dl | |
835 | test_fork1 | |
836 | test_gettext | |
837 | test_gl | |
838 | test_imgfile | |
839 | test_largefile | |
840 | test_linuxaudiodev | |
841 | test_locale | |
842 | test_minidom | |
843 | test_nis | |
844 | test_ntpath | |
845 | test_openpty | |
846 | test_pyexpat | |
847 | test_queue | |
848 | test_sax | |
849 | test_sunaudiodev | |
850 | test_sundry | |
851 | test_thread | |
852 | test_threaded_import | |
853 | test_threadedtempfile | |
854 | test_threading | |
855 | """, | |
856 | 'riscos': | |
857 | """ | |
858 | test_al | |
859 | test_applesingle | |
860 | test_asynchat | |
861 | test_atexit | |
862 | test_bsddb | |
863 | test_bsddb185 | |
864 | test_bsddb3 | |
865 | test_cd | |
866 | test_cl | |
867 | test_commands | |
868 | test_crypt | |
869 | test_dbm | |
870 | test_dl | |
871 | test_fcntl | |
872 | test_fork1 | |
873 | test_gdbm | |
874 | test_gl | |
875 | test_grp | |
876 | test_imgfile | |
877 | test_largefile | |
878 | test_linuxaudiodev | |
879 | test_locale | |
880 | test_mmap | |
881 | test_nis | |
882 | test_ntpath | |
883 | test_openpty | |
884 | test_poll | |
885 | test_popen2 | |
886 | test_pty | |
887 | test_pwd | |
888 | test_strop | |
889 | test_sunaudiodev | |
890 | test_sundry | |
891 | test_thread | |
892 | test_threaded_import | |
893 | test_threadedtempfile | |
894 | test_threading | |
895 | test_timing | |
896 | """, | |
897 | 'darwin': | |
898 | """ | |
899 | test__locale | |
900 | test_al | |
901 | test_bsddb | |
902 | test_bsddb3 | |
903 | test_cd | |
904 | test_cl | |
905 | test_curses | |
906 | test_dl | |
907 | test_gdbm | |
908 | test_gl | |
909 | test_imgfile | |
910 | test_largefile | |
911 | test_linuxaudiodev | |
912 | test_locale | |
913 | test_minidom | |
914 | test_nis | |
915 | test_ntpath | |
916 | test_ossaudiodev | |
917 | test_poll | |
918 | test_sunaudiodev | |
919 | """, | |
920 | 'sunos5': | |
921 | """ | |
922 | test_al | |
923 | test_applesingle | |
924 | test_bsddb | |
925 | test_bsddb185 | |
926 | test_cd | |
927 | test_cl | |
928 | test_curses | |
929 | test_dbm | |
930 | test_gdbm | |
931 | test_gl | |
932 | test_gzip | |
933 | test_imgfile | |
934 | test_linuxaudiodev | |
935 | test_openpty | |
936 | test_zipfile | |
937 | test_zlib | |
938 | """, | |
939 | 'hp-ux11': | |
940 | """ | |
941 | test_al | |
942 | test_applesingle | |
943 | test_bsddb | |
944 | test_bsddb185 | |
945 | test_cd | |
946 | test_cl | |
947 | test_curses | |
948 | test_dl | |
949 | test_gdbm | |
950 | test_gl | |
951 | test_gzip | |
952 | test_imgfile | |
953 | test_largefile | |
954 | test_linuxaudiodev | |
955 | test_locale | |
956 | test_minidom | |
957 | test_nis | |
958 | test_ntpath | |
959 | test_openpty | |
960 | test_pyexpat | |
961 | test_sax | |
962 | test_sunaudiodev | |
963 | test_zipfile | |
964 | test_zlib | |
965 | """, | |
966 | 'atheos': | |
967 | """ | |
968 | test_al | |
969 | test_applesingle | |
970 | test_bsddb185 | |
971 | test_cd | |
972 | test_cl | |
973 | test_curses | |
974 | test_dl | |
975 | test_gdbm | |
976 | test_gl | |
977 | test_imgfile | |
978 | test_largefile | |
979 | test_linuxaudiodev | |
980 | test_locale | |
981 | test_mhlib | |
982 | test_mmap | |
983 | test_nis | |
984 | test_poll | |
985 | test_popen2 | |
986 | test_resource | |
987 | test_sunaudiodev | |
988 | """, | |
989 | 'cygwin': | |
990 | """ | |
991 | test_al | |
992 | test_applesingle | |
993 | test_bsddb185 | |
994 | test_bsddb3 | |
995 | test_cd | |
996 | test_cl | |
997 | test_curses | |
998 | test_dbm | |
999 | test_gl | |
1000 | test_imgfile | |
1001 | test_ioctl | |
1002 | test_largefile | |
1003 | test_linuxaudiodev | |
1004 | test_locale | |
1005 | test_nis | |
1006 | test_ossaudiodev | |
1007 | test_socketserver | |
1008 | test_sunaudiodev | |
1009 | """, | |
1010 | 'os2emx': | |
1011 | """ | |
1012 | test_al | |
1013 | test_applesingle | |
1014 | test_audioop | |
1015 | test_bsddb185 | |
1016 | test_bsddb3 | |
1017 | test_cd | |
1018 | test_cl | |
1019 | test_commands | |
1020 | test_curses | |
1021 | test_dl | |
1022 | test_gl | |
1023 | test_imgfile | |
1024 | test_largefile | |
1025 | test_linuxaudiodev | |
1026 | test_mhlib | |
1027 | test_mmap | |
1028 | test_nis | |
1029 | test_openpty | |
1030 | test_ossaudiodev | |
1031 | test_pty | |
1032 | test_resource | |
1033 | test_signal | |
1034 | test_sunaudiodev | |
1035 | """, | |
1036 | 'freebsd4': | |
1037 | """ | |
1038 | test_aepack | |
1039 | test_al | |
1040 | test_applesingle | |
1041 | test_bsddb | |
1042 | test_bsddb3 | |
1043 | test_cd | |
1044 | test_cl | |
1045 | test_gdbm | |
1046 | test_gl | |
1047 | test_imgfile | |
1048 | test_linuxaudiodev | |
1049 | test_locale | |
1050 | test_macfs | |
1051 | test_macostools | |
1052 | test_nis | |
1053 | test_normalization | |
1054 | test_ossaudiodev | |
1055 | test_pep277 | |
1056 | test_plistlib | |
1057 | test_pty | |
1058 | test_scriptpackages | |
1059 | test_socket_ssl | |
1060 | test_socketserver | |
1061 | test_sunaudiodev | |
1062 | test_tcl | |
1063 | test_timeout | |
1064 | test_unicode_file | |
1065 | test_urllibnet | |
1066 | test_winreg | |
1067 | test_winsound | |
1068 | """, | |
1069 | 'aix5': | |
1070 | """ | |
1071 | test_aepack | |
1072 | test_al | |
1073 | test_applesingle | |
1074 | test_bsddb | |
1075 | test_bsddb185 | |
1076 | test_bsddb3 | |
1077 | test_bz2 | |
1078 | test_cd | |
1079 | test_cl | |
1080 | test_dl | |
1081 | test_gdbm | |
1082 | test_gl | |
1083 | test_gzip | |
1084 | test_imgfile | |
1085 | test_linuxaudiodev | |
1086 | test_macfs | |
1087 | test_macostools | |
1088 | test_nis | |
1089 | test_ossaudiodev | |
1090 | test_sunaudiodev | |
1091 | test_tcl | |
1092 | test_winreg | |
1093 | test_winsound | |
1094 | test_zipimport | |
1095 | test_zlib | |
1096 | """, | |
1097 | } | |
1098 | _expectations['freebsd5'] = _expectations['freebsd4'] | |
1099 | _expectations['freebsd6'] = _expectations['freebsd4'] | |
1100 | ||
1101 | class _ExpectedSkips: | |
1102 | def __init__(self): | |
1103 | import os.path | |
1104 | from test import test_normalization | |
1105 | from test import test_socket_ssl | |
1106 | from test import test_timeout | |
1107 | from test import test_codecmaps_cn, test_codecmaps_jp | |
1108 | from test import test_codecmaps_kr, test_codecmaps_tw | |
1109 | from test import test_codecmaps_hk | |
1110 | ||
1111 | self.valid = False | |
1112 | if sys.platform in _expectations: | |
1113 | s = _expectations[sys.platform] | |
1114 | self.expected = set(s.split()) | |
1115 | ||
1116 | if not os.path.supports_unicode_filenames: | |
1117 | self.expected.add('test_pep277') | |
1118 | ||
1119 | if test_normalization.skip_expected: | |
1120 | self.expected.add('test_normalization') | |
1121 | ||
1122 | if test_socket_ssl.skip_expected: | |
1123 | self.expected.add('test_socket_ssl') | |
1124 | ||
1125 | if test_timeout.skip_expected: | |
1126 | self.expected.add('test_timeout') | |
1127 | ||
1128 | for cc in ('cn', 'jp', 'kr', 'tw', 'hk'): | |
1129 | if eval('test_codecmaps_' + cc).skip_expected: | |
1130 | self.expected.add('test_codecmaps_' + cc) | |
1131 | ||
1132 | if sys.maxint == 9223372036854775807L: | |
1133 | self.expected.add('test_rgbimg') | |
1134 | self.expected.add('test_imageop') | |
1135 | ||
1136 | if not sys.platform in ("mac", "darwin"): | |
1137 | MAC_ONLY = ["test_macostools", "test_macfs", "test_aepack", | |
1138 | "test_plistlib", "test_scriptpackages"] | |
1139 | for skip in MAC_ONLY: | |
1140 | self.expected.add(skip) | |
1141 | ||
1142 | if sys.platform != "win32": | |
1143 | WIN_ONLY = ["test_unicode_file", "test_winreg", | |
1144 | "test_winsound"] | |
1145 | for skip in WIN_ONLY: | |
1146 | self.expected.add(skip) | |
1147 | ||
1148 | self.valid = True | |
1149 | ||
1150 | def isvalid(self): | |
1151 | "Return true iff _ExpectedSkips knows about the current platform." | |
1152 | return self.valid | |
1153 | ||
1154 | def getexpected(self): | |
1155 | """Return set of test names we expect to skip on current platform. | |
1156 | ||
1157 | self.isvalid() must be true. | |
1158 | """ | |
1159 | ||
1160 | assert self.isvalid() | |
1161 | return self.expected | |
1162 | ||
1163 | if __name__ == '__main__': | |
1164 | # Remove regrtest.py's own directory from the module search path. This | |
1165 | # prevents relative imports from working, and relative imports will screw | |
1166 | # up the testing framework. E.g. if both test.test_support and | |
1167 | # test_support are imported, they will not contain the same globals, and | |
1168 | # much of the testing framework relies on the globals in the | |
1169 | # test.test_support module. | |
1170 | mydir = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0]))) | |
1171 | i = pathlen = len(sys.path) | |
1172 | while i >= 0: | |
1173 | i -= 1 | |
1174 | if os.path.abspath(os.path.normpath(sys.path[i])) == mydir: | |
1175 | del sys.path[i] | |
1176 | if len(sys.path) == pathlen: | |
1177 | print 'Could not find %r in sys.path to remove it' % mydir | |
1178 | main() |