# HG changeset patch # User Oleg Oshmyan # Date 1292780060 -7200 # Node ID 5afefe51dcdc370830b5380f9ec28c81ff202c60 # Parent e92e6d4aa2ef6cbb7650a22c0b954cc72c3288ec Initial rename to Upreckon Bonus: eliminated the last remaining mentions of Subversion. diff -r e92e6d4aa2ef -r 5afefe51dcdc 2.00/publish.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/2.00/publish.sh Sun Dec 19 19:34:20 2010 +0200 @@ -0,0 +1,11 @@ +#! /bin/sh + +VERSION=`hg summary | grep '^parent' | sed -En 's/^parent: [0-9]*:([0-9a-f]+) .*$/\1/p'` +if [ -z "$VERSION" ] +then + echo The current Mercurial changeset could not be determined. >&2 + exit 1 +fi + +sed 's/$$REV$\$/hg '"$VERSION/" upreckon-vcs >upreckon +chmod +x upreckon \ No newline at end of file diff -r e92e6d4aa2ef -r 5afefe51dcdc 2.00/test-svn.py --- a/2.00/test-svn.py Thu Dec 09 19:05:06 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -#! /usr/bin/env python -# Copyright (c) 2009-2010 Chortos-2 - -from __future__ import division, with_statement -import optparse, sys, compat - -def import_error(e): - say('Error: your installation of test.py is incomplete;', str(e).lower() + '.', file=sys.stderr) - sys.exit(3) - -from compat import * - -version = '2.00.0 ($$REV$$)' -parser = optparse.OptionParser(version='test.py '+version, epilog='Python 2.5 or newer is required.') -parser.add_option('-1', dest='legacy', action='store_true', default=False, help='handle configuration files in a way more compatible with test.py 1.x') -parser.add_option('-u', '--update', dest='update', action='store_true', default=False, help='update the installed test.py to the latest publicly available version') -parser.add_option('-p', '--problem', dest='problems', metavar='PROBLEM', action='append', help='test only the PROBLEM (this option can be specified more than once with different problem names, all of which will be tested)') -parser.add_option('-m', '--copy-io', dest='copyonly', action='store_true', default=False, help='create a copy of the input/output files of the last test case for manual testing and exit') -parser.add_option('-x', '--auto-exit', dest='pause', action='store_false', default=True, help='do not wait for a key to be pressed after finishing testing') -parser.add_option('-s', '--save-io', dest='erase', action='store_false', default=True, help='do not delete the copies of input/output files after the last test case; create copies of input files and store output in files even if the solution uses standard I/O; delete the stored input/output files if the solution uses standard I/O and the -c/--cleanup option is specified') -parser.add_option('-t', '--detect-time', dest='autotime', action='store_true', default=False, help='spend a second detecting the most precise time measurement function') -parser.add_option('--no-time-limits', dest='no_maxtime', action='store_true', default=False, help='disable all time limits') - -options, args = parser.parse_args() -parser.destroy() -del parser - -if options.update: - try: - urllib, urlread = compat.import_urllib() - except ImportError: - sys.exit('Error: the urllib Python module is missing. Without it, an automatic update is impossible.') - - latesttext = urlread('http://chortos.selfip.net/~astiob/test.py/version.txt') - latest = latesttext.split('.') - installed = version.split('.') - update = None - - if latest[0] > installed[0]: - update = 'major' - elif latest[0] == installed[0]: - if latest[1] > installed[1]: - update = 'feature' - elif latest[1] == installed[1]: - if latest[2] > installed[2]: - update = 'bug-fixing' - elif latest[2] == installed[2]: - say('You are using the latest publicly available version of test.py.') - sys.exit() - - if not update: - say('Your copy of test.py is newer than the publicly available version.') - sys.exit() - - say('A ' + update + ' update to test.py is available. Downloading...') - sys.stdout.flush() - urllib.urlretrieve('http://chortos.selfip.net/~astiob/test.py/test.py', sys.argv[0]) - say('Downloaded and installed. Now you are using test.py ' + latesttext + '.') - sys.exit() - -import config, itertools, os, subprocess, sys, time - -if options.autotime: - # This is really a dirty hack that assumes that sleep() does not spend - # the CPU time of the current process and that if clock() measures - # wall-clock time, then it is more precise than time() is. Both these - # assumptions are true on all platforms I have tested this on so far, - # but I am not aware of any guarantee that they will both be true - # on every other platform. - c = time.clock() - time.sleep(1) - c = time.clock() - c - if int(c + .5) == 1: - clock = time.clock - else: - clock = time.time -elif sys.platform == 'win32': - clock = time.clock -else: - clock = time.time - -try: - from testcases import pause -except ImportError: - pause = None - -try: - globalconf = config.load_global() - - # Do this check here so that if we have to warn them, we do it as early as possible - if options.pause and not pause and not hasattr(globalconf, 'pause'): - if os.name == 'posix': - globalconf.pause = 'read -s -n 1' - say('Warning: configuration variable pause is not defined; it was devised automatically but the choice might be incorrect, so test.py might exit immediately after the testing is completed.', file=sys.stderr) - sys.stderr.flush() - elif os.name == 'nt': - globalconf.pause = 'pause' - else: - sys.exit('Error: configuration variable pause is not defined and cannot be devised automatically.') - - try: - from problem import * - except ImportError: - import_error(sys.exc_info()[1]) - - # Support single-problem configurations - if globalconf.tasknames is None: - shouldprintnames = False - globalconf.multiproblem = False - globalconf.tasknames = os.path.curdir, - else: - globalconf.multiproblem = True - shouldprintnames = True - - ntasks = 0 - nfulltasks = 0 - maxscore = 0 - realscore = 0 - - for taskname in (globalconf.tasknames if not options.problems else options.problems): - problem = Problem(taskname) - - if ntasks and not options.copyonly: say() - if shouldprintnames: say(taskname) - - if options.copyonly: - problem.copytestdata() - else: - real, max = problem.test() - - ntasks += 1 - nfulltasks += real == max - realscore += real - maxscore += max - - if options.copyonly: - sys.exit() - - if ntasks != 1: - say() - say('Grand grand total: %g/%g weighted points; %d/%d problems solved fully' % (realscore, maxscore, nfulltasks, ntasks)) -except KeyboardInterrupt: - sys.exit('Exiting due to a keyboard interrupt.') - -if options.pause: - say('Press any key to exit...') - sys.stdout.flush() - - if pause: - pause() - elif callable(globalconf.pause): - globalconf.pause() - else: - with open(os.devnull, 'w') as devnull: - subprocess.call(globalconf.pause, stdout=devnull, stderr=subprocess.STDOUT) \ No newline at end of file diff -r e92e6d4aa2ef -r 5afefe51dcdc 2.00/test.py.sublime-project --- a/2.00/test.py.sublime-project Thu Dec 09 19:05:06 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ - - - - - - - - diff -r e92e6d4aa2ef -r 5afefe51dcdc 2.00/upreckon-vcs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/2.00/upreckon-vcs Sun Dec 19 19:34:20 2010 +0200 @@ -0,0 +1,156 @@ +#! /usr/bin/env python +# Copyright (c) 2009-2010 Chortos-2 + +from __future__ import division, with_statement +import optparse, sys, compat + +def import_error(e): + say('Error: your installation of Upreckon is incomplete;', str(e).lower() + '.', file=sys.stderr) + sys.exit(3) + +from compat import * + +version = '2.00.0 ($$REV$$)' +parser = optparse.OptionParser(version='Upreckon '+version, epilog='Python 2.5 or newer is required.') +parser.add_option('-1', dest='legacy', action='store_true', default=False, help='handle configuration files in a way more compatible with test.py 1.x') +parser.add_option('-u', '--update', dest='update', action='store_true', default=False, help='update the installed Upreckon to the latest publicly available version') +parser.add_option('-p', '--problem', dest='problems', metavar='PROBLEM', action='append', help='test only the PROBLEM (this option can be specified more than once with different problem names, all of which will be tested)') +parser.add_option('-m', '--copy-io', dest='copyonly', action='store_true', default=False, help='create a copy of the input/output files of the last test case for manual testing and exit') +parser.add_option('-x', '--auto-exit', dest='pause', action='store_false', default=True, help='do not wait for a key to be pressed after finishing testing') +parser.add_option('-s', '--save-io', dest='erase', action='store_false', default=True, help='do not delete the copies of input/output files after the last test case; create copies of input files and store output in files even if the solution uses standard I/O; delete the stored input/output files if the solution uses standard I/O and the -c/--cleanup option is specified') +parser.add_option('-t', '--detect-time', dest='autotime', action='store_true', default=False, help='spend a second detecting the most precise time measurement function') +parser.add_option('--no-time-limits', dest='no_maxtime', action='store_true', default=False, help='disable all time limits') + +options, args = parser.parse_args() +parser.destroy() +del parser + +if options.update: + try: + urllib, urlread = compat.import_urllib() + except ImportError: + sys.exit('Error: the urllib Python module is missing. Without it, an automatic update is impossible.') + + latesttext = urlread('http://chortos.selfip.net/~astiob/test.py/version.txt') + latest = latesttext.split('.') + installed = version.split('.') + update = None + + if latest[0] > installed[0]: + update = 'major' + elif latest[0] == installed[0]: + if latest[1] > installed[1]: + update = 'feature' + elif latest[1] == installed[1]: + if latest[2] > installed[2]: + update = 'bug-fixing' + elif latest[2] == installed[2]: + say('You are using the latest publicly available version of Upreckon.') + sys.exit() + + if not update: + say('Your copy of Upreckon is newer than the publicly available version.') + sys.exit() + + say('A ' + update + ' update to Upreckon is available. Downloading...') + sys.stdout.flush() + # FIXME: need to update all files! + urllib.urlretrieve('http://chortos.selfip.net/~astiob/test.py/test.py', sys.argv[0]) + say('Downloaded and installed. Now you are using Upreckon ' + latesttext + '.') + sys.exit() + +import config, itertools, os, subprocess, sys, time + +if options.autotime: + # This is really a dirty hack that assumes that sleep() does not spend + # the CPU time of the current process and that if clock() measures + # wall-clock time, then it is more precise than time() is. Both these + # assumptions are true on all platforms I have tested this on so far, + # but I am not aware of any guarantee that they will both be true + # on every other platform. + c = time.clock() + time.sleep(1) + c = time.clock() - c + if int(c + .5) == 1: + clock = time.clock + else: + clock = time.time +elif sys.platform == 'win32': + clock = time.clock +else: + clock = time.time + +try: + from testcases import pause +except ImportError: + pause = None + +try: + globalconf = config.load_global() + + # Do this check here so that if we have to warn them, we do it as early as possible + if options.pause and not pause and not hasattr(globalconf, 'pause'): + if os.name == 'posix': + globalconf.pause = 'read -s -n 1' + say('Warning: configuration variable pause is not defined; it was devised automatically but the choice might be incorrect, so Upreckon might exit immediately after the testing is completed.', file=sys.stderr) + sys.stderr.flush() + elif os.name == 'nt': + globalconf.pause = 'pause' + else: + sys.exit('Error: configuration variable pause is not defined and cannot be devised automatically.') + + try: + from problem import * + except ImportError: + import_error(sys.exc_info()[1]) + + # Support single-problem configurations + if globalconf.tasknames is None: + shouldprintnames = False + globalconf.multiproblem = False + globalconf.tasknames = os.path.curdir, + else: + globalconf.multiproblem = True + shouldprintnames = True + + ntasks = 0 + nfulltasks = 0 + maxscore = 0 + realscore = 0 + + for taskname in (globalconf.tasknames if not options.problems else options.problems): + problem = Problem(taskname) + + if ntasks and not options.copyonly: say() + if shouldprintnames: say(taskname) + + if options.copyonly: + problem.copytestdata() + else: + real, max = problem.test() + + ntasks += 1 + nfulltasks += real == max + realscore += real + maxscore += max + + if options.copyonly: + sys.exit() + + if ntasks != 1: + say() + say('Grand grand total: %g/%g weighted points; %d/%d problems solved fully' % (realscore, maxscore, nfulltasks, ntasks)) +except KeyboardInterrupt: + sys.exit('Exiting due to a keyboard interrupt.') + +if options.pause: + say('Press any key to exit...') + sys.stdout.flush() + + if pause: + pause() + elif callable(globalconf.pause): + globalconf.pause() + else: + with open(os.devnull, 'w') as devnull: + subprocess.call(globalconf.pause, stdout=devnull, stderr=subprocess.STDOUT) \ No newline at end of file diff -r e92e6d4aa2ef -r 5afefe51dcdc 2.00/upreckon.sublime-project --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/2.00/upreckon.sublime-project Sun Dec 19 19:34:20 2010 +0200 @@ -0,0 +1,10 @@ + + + + + + + + diff -r e92e6d4aa2ef -r 5afefe51dcdc publish.sh --- a/publish.sh Thu Dec 09 19:05:06 2010 +0200 +++ b/publish.sh Sun Dec 19 19:34:20 2010 +0200 @@ -7,5 +7,5 @@ exit 1 fi -sed 's/$$REV$\$/hg '"$VERSION/" test-svn.py >test.py +sed 's/$$REV$\$/hg '"$VERSION/" test-vcs.py >test.py chmod +x test.py \ No newline at end of file diff -r e92e6d4aa2ef -r 5afefe51dcdc test-svn.py --- a/test-svn.py Thu Dec 09 19:05:06 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,969 +0,0 @@ -#! /usr/bin/python -# Copyright (c) 2009-2010 Chortos-2 - -import os, sys, shutil, time, subprocess, filecmp, optparse, signal, tempfile, tarfile, zipfile - -version = '1.21.0 ($$REV$$)' -parser = optparse.OptionParser(version='test.py '+version, usage='usage: %prog [options] [problem names] [[path' + os.path.sep + 'to' + os.path.sep + ']solution-app] [test case numbers]\n\nTest case numbers can be specified in plain text or as a Python expression\nif there is only one positional argument.\n\nOnly problem names listed in testconf.py are recognized.') -parser.add_option('-u', '--update', dest='update', action='store_true', default=False, help='check for an updated version of test.py') -parser.add_option('-e', '--exclude', dest='exclude', action='append', help='test case number(s) to exclude, as a Python expression; multiple -e options can be supplied') -parser.add_option('-c', '--cleanup', dest='clean', action='store_true', default=False, help='delete the copies of input/output files and exit') -parser.add_option('-s', '--save-io', dest='erase', action='store_false', default=True, help='do not delete the copies of input/output files after the last test case; create copies of input files and store output in files even if the solution uses standard I/O; delete the stored input/output files if the solution uses standard I/O and the -c/--cleanup option is specified') -parser.add_option('-m', '--copy-io', dest='copyonly', action='store_true', default=False, help='only create a copy of the input/output files of the last test case for manual testing; to delete them, use options -cs or -cm') -parser.add_option('-x', '--auto-exit', dest='pause', action='store_false', default=True, help='do not wait for a key to be pressed when finished testing') -parser.add_option('-p', '--python', action='store_true', default=False, help='always parse all positional arguments as a single Python expression (including the first argument even if it names an executable file)') -parser.add_option('-t', '--detect-time', dest='autotime', action='store_true', default=False, help='spend a second detecting the most precise time measurement function') -parser.add_option('-b', dest='builtin', action='store_true', default=False) - -options, args = parser.parse_args() -parser.destroy() -del parser - -if options.builtin: - try: - if args[0] == 'run': - import resource - maxmemory = int(args[1]) - resource.setrlimit(resource.RLIMIT_AS, (maxmemory*1024**2, maxmemory*1024**2)) - os.execv(args[2], args[2:]) - else: - sys.exit(2) - except: - sys.exit(2) - -def update(): - import urllib - latesttext = urllib.urlopen('http://chortos.selfip.net/~astiob/test.py/version.txt').read() - latest = latesttext.split('.') - installed = version.split('.') - update = '' - if latest[0] > installed[0]: - update = 'major' - elif latest[0] == installed[0]: - if latest[1] > installed[1]: - update = 'feature' - elif latest[1] == installed[1]: - if latest[2] > installed[2]: - update = 'bug-fixing' - elif latest[2] == installed[2]: - print 'You are using the latest publicly available version of test.py.' - return - if update == '': - print 'Your copy of test.py is newer than the publicly available version.' - return - print 'A ' + update + ' update to test.py is available. Downloading...' - sys.stdout.flush() - urllib.urlretrieve('http://chortos.selfip.net/~astiob/test.py/test.py', 'test.py') - print 'Downloaded and installed. Now you are using test.py ' + latesttext + '.' - -if options.update: - update() - sys.exit() - -try: - import resource - memlimit = True - def call(name): - pid = os.fork() - if not pid: - resource.setrlimit(resource.RLIMIT_AS, (maxmemory*1024**2, maxmemory*1024**2)) - os.execl(name) - else: - return pid -except ImportError: - memlimit = False - -globals1 = set(globals()) - -# Initialize some configuration variables with default values -tasknames = (os.path.curdir,) -maxtime = 0 -tests = () -dummies = () -testsexcluded = () -padwithzeroestolength = 0 -taskweight = 100 -pointmap = {} -stdio = False -dummyinname = '' -dummyoutname = '' -tester = '' -maxexitcode = 0 - -def exectestconf_helper(name): - if os.path.isfile('tests.tar'): - f = tarfile.open('tests.tar') - try: - exec f.extractfile(name).read() in globals() - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.zip'): - f = zipfile.ZipFile('tests.zip') - try: - exec f.open(name, 'rU').read() in globals() - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.tgz'): - f = tarfile.open('tests.tgz') - try: - exec f.extractfile(name).read() in globals() - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.tar.gz'): - f = tarfile.open('tests.tar.gz') - try: - exec f.extractfile(name).read() in globals() - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.tbz2'): - f = tarfile.open('tests.tbz2') - try: - exec f.extractfile(name).read() in globals() - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.tar.bz2'): - f = tarfile.open('tests.tar.bz2') - try: - exec f.extractfile(name).read() in globals() - f.close() - return True - except KeyError: - f.close() - return False - -try: - execfile('testconf.py') -except IOError, error: - exc_info = sys.exc_info()[2] - try: - execfile(os.path.join('tests', 'testconf.py')) - except IOError: - if not exectestconf_helper('testconf.py'): - raise IOError, (error.errno, 'The configuration file is missing', error.filename), exc_info - del exc_info - -globals2 = set(globals()) -globals2.remove('globals1') -globals2 -= globals1 -del globals1 - -shared = {} -g = globals() -for k in globals2: - shared[k] = g[k] - -newtasknames = [] -while len(args) and args[0] in tasknames: - newtasknames.append(args[0]) - del args[0] -if len(newtasknames): - tasknames = newtasknames - -scoresumoveralltasks = 0 -scoremaxoveralltasks = 0 -ntasks = 0 -nfulltasks = 0 -cwd = '' # At any time this is either '' or taskname - -if options.autotime: - c = time.clock() - time.sleep(1) - c = time.clock() - c - if int(c + .99999) == 1: - clock = time.clock - else: - clock = time.time -elif os.name == 'nt': - clock = time.clock -else: - clock = time.time - -if options.copyonly: - options.erase = False - -def existstestcase_helper(name): - if os.path.isfile('tests.tar'): - f = tarfile.open('tests.tar') - try: - f.getmember(name) - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.zip'): - f = zipfile.ZipFile('tests.zip') - try: - f.getinfo(name) - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.tgz'): - f = tarfile.open('tests.tgz') - try: - f.getmember(name) - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.tar.gz'): - f = tarfile.open('tests.tar.gz') - try: - f.getmember(name) - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.tbz2'): - f = tarfile.open('tests.tbz2') - try: - f.getmember(name) - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.tar.bz2'): - f = tarfile.open('tests.tar.bz2') - try: - f.getmember(name) - f.close() - return True - except KeyError: - f.close() - return False - -def existstestcase(name): - if os.path.isfile(os.path.join('tests', taskname, name)) or os.path.isfile(os.path.join('tests', name)): - return True - if cwd and (os.path.isfile(os.path.join(oldcwd, 'tests', cwd, name)) or os.path.isfile(os.path.join(oldcwd, 'tests', name))): - return True - if existstestcase_helper(os.path.join(taskname, name)) or existstestcase_helper(name): - return True - if cwd: - os.chdir(oldcwd) - if existstestcase_helper(os.path.join(cwd, name)) or existstestcase_helper(name): - os.chdir(cwd) - return True - os.chdir(cwd) - return False - -def opentestcase_helper(name): - if os.path.isfile('tests.tar'): - f = tarfile.open('tests.tar') - try: - c = f.extractfile(name) - return c - except KeyError: - f.close() - if os.path.isfile('tests.zip'): - f = zipfile.ZipFile('tests.zip') - try: - c = f.open(name, 'rU') - f.close() - return c - except KeyError: - f.close() - if os.path.isfile('tests.tgz'): - f = tarfile.open('tests.tgz') - try: - c = f.extractfile(name) - return c - except KeyError: - f.close() - if os.path.isfile('tests.tar.gz'): - f = tarfile.open('tests.tar.gz') - try: - c = f.extractfile(name) - return c - except KeyError: - f.close() - if os.path.isfile('tests.tbz2'): - f = tarfile.open('tests.tbz2') - try: - c = f.extractfile(name) - return c - except KeyError: - f.close() - if os.path.isfile('tests.tar.bz2'): - f = tarfile.open('tests.tar.bz2') - try: - c = f.extractfile(name) - return c - except KeyError: - f.close() - return None - -def opentestcase(name): - if os.path.isfile(os.path.join('tests', taskname, name)): - return open(os.path.join('tests', taskname, name), 'rU') - elif os.path.isfile(os.path.join('tests', name)): - return open(os.path.join('tests', name), 'rU') - f = opentestcase_helper(os.path.join(taskname, name)) - if not f: - f = opentestcase_helper(name) - if f: - return f - if cwd: - if os.path.isfile(os.path.join(oldcwd, 'tests', cwd, name)): - return open(os.path.join(oldcwd, 'tests', cwd, name), 'rU') - elif os.path.isfile(os.path.join(oldcwd, 'tests', name)): - return open(os.path.join(oldcwd, 'tests', name), 'rU') - os.chdir(oldcwd) - f = opentestcase_helper(os.path.join(cwd, name)) - if not f: - f = opentestcase_helper(name) - os.chdir(cwd) - if f: - return f - raise KeyError, 'The test-case-defining file \'' + name + '\' cannot be found' - -def copytestcase_helper(name, target): - if os.path.isfile('tests.tar'): - f = tarfile.open('tests.tar') - try: - m = f.getmember(name) - m.name = target - f.extract(m) - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.zip'): - if not os.path.isabs(target): - f = zipfile.ZipFile('tests.zip') - try: - m = f.getinfo(name) - m.filename = target - f.extract(m) - f.close() - return True - except KeyError: - f.close() - else: - oldcwd = os.getcwdu() - os.chdir('/') # FIXME: portability? - f = zipfile.ZipFile(os.path.join(oldcwd, 'tests.zip')) - try: - m = f.getinfo(name) - m.filename = os.path.relpath(target) - f.extract(m) - f.close() - os.chdir(oldcwd) - return True - except KeyError: - f.close() - os.chdir(oldcwd) - if os.path.isfile('tests.tgz'): - f = tarfile.open('tests.tgz') - try: - m = f.getmember(name) - m.name = target - f.extract(m) - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.tar.gz'): - f = tarfile.open('tests.tar.gz') - try: - m = f.getmember(name) - m.name = target - f.extract(m) - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.tbz2'): - f = tarfile.open('tests.tbz2') - try: - m = f.getmember(name) - m.name = target - f.extract(m) - f.close() - return True - except KeyError: - f.close() - if os.path.isfile('tests.tar.bz2'): - f = tarfile.open('tests.tar.bz2') - try: - m = f.getmember(name) - m.name = target - f.extract(m) - f.close() - return True - except KeyError: - f.close() - return False - -def copytestcase(name, target): - if os.path.isfile(os.path.join('tests', taskname, name)): - shutil.copyfile(os.path.join('tests', taskname, name), target) - return - elif os.path.isfile(os.path.join('tests', name)): - shutil.copyfile(os.path.join('tests', name), target) - return - if copytestcase_helper(os.path.join(taskname, name), target) or copytestcase_helper(name, target): - return - if cwd: - if os.path.isfile(os.path.join(oldcwd, 'tests', cwd, name)): - shutil.copyfile(os.path.join(oldcwd, 'tests', cwd, name), target) - return - elif os.path.isfile(os.path.join(oldcwd, 'tests', name)): - shutil.copyfile(os.path.join(oldcwd, 'tests', name), target) - return - os.chdir(oldcwd) - if copytestcase_helper(os.path.join(cwd, name), target) or copytestcase_helper(name, target): - os.chdir(cwd) - return - os.chdir(cwd) - raise KeyError, 'The test-case-defining file \'' + name + '\' cannot be found' - -# Always chdir if the directory exists but use any existing config -def chdir_and_exec_testconf(): - global cwd - cwd = '' - if os.path.isdir(taskname): - os.chdir(taskname) - if taskname != os.path.curdir: - cwd = taskname - try: - execfile('testconf.py', globals()) - return - except IOError: - pass - if not cwd: - if os.path.isfile(os.path.join('tests', taskname, 'testconf.py')): - execfile(os.path.join('tests', taskname, 'testconf.py'), globals()) - return - if os.path.isfile(os.path.join('tests', 'testconf.py')): - execfile(os.path.join('tests', 'testconf.py'), globals()) - return - if exectestconf_helper(os.path.join(taskname, 'testconf.py')) or exectestconf_helper('testconf.py'): - return - if cwd: - os.chdir(oldcwd) - if os.path.isfile(os.path.join('tests', cwd, 'testconf.py')): - execfile(os.path.join('tests', cwd, 'testconf.py'), globals()) - os.chdir(cwd) - return - if os.path.isfile(os.path.join('tests', 'testconf.py')): - execfile(os.path.join('tests', 'testconf.py'), globals()) - os.chdir(cwd) - return - if exectestconf_helper(os.path.join(cwd, 'testconf.py')) or exectestconf_helper('testconf.py'): - os.chdir(cwd) - return - if os.path.isfile('testconf.py'): - execfile('testconf.py', globals()) - os.chdir(cwd) - return - os.chdir(cwd) - elif os.path.isfile('testconf.py'): - execfile('testconf.py', globals()) - return - raise KeyError, 'The configuration file for task ' + taskname + ' is missing' - -try: - name - namedefined = True -except Exception: - namedefined = False - -for taskname in tasknames: - if ntasks: - print - - try: - if len(tasknames) > 1: - print taskname - except Exception: - if taskname != os.path.curdir or ntasks: - print taskname - - try: del inname - except NameError: pass - try: del outname - except NameError: pass - try: del ansname - except NameError: pass - - if not namedefined and taskname != os.path.curdir: - name = os.path.join(os.path.curdir, taskname) - for k in shared: - g[k] = shared[k] - - oldcwd = os.getcwdu() - chdir_and_exec_testconf() - - if options.clean: - try: - if not stdio or tester: - if not tester: - inname - outname - if tester: - ansname - except NameError, error: - raise NameError, 'configuration ' + str(error).replace('name ', 'variable ', 1), sys.exc_info()[2] - if not options.erase: - try: - inname = inname.replace('%', taskname) - except NameError: - inname = taskname + '.in' - try: - outname = outname.replace('%', taskname) - except NameError: - outname = taskname + '.out' - try: - ansname = ansname.replace('%', taskname) - except NameError: - ansname = taskname + '.ans' - elif not stdio or tester or not options.erase: - inname = inname.replace('%', taskname) - outname = outname.replace('%', taskname) - if tester: - ansname = ansname.replace('%', taskname) - if not stdio or tester or not options.erase: - if os.path.exists(inname): os.remove(inname) - if os.path.exists(outname): os.remove(outname) - if (tester or not options.erase) and ansname: - if os.path.exists(ansname): os.remove(ansname) - continue - - try: - name - except NameError, error: - if str(error).count('name') == 1: - raise NameError, 'configuration ' + str(error), sys.exc_info()[2] - else: - raise NameError, 'configuration ' + str(error).replace('name ', 'variable ', 1), sys.exc_info()[2] - - try: - if not stdio: - inname - outname - testcaseinname - if tester: - outname - if ansname: - testcaseoutname - else: - testcaseoutname - except NameError, error: - raise NameError, 'configuration ' + str(error).replace('name ', 'variable ', 1), sys.exc_info()[2] - - if not options.erase: - try: - inname - except NameError: - inname = taskname + '.in' - try: - outname - except NameError: - outname = taskname + '.out' - try: - ansname - except NameError: - ansname = taskname + '.ans' - - if options.pause: - try: - pause - except NameError, error: - if os.name == 'posix': - pause = 'read -s -n 1' - print 'Configuration ' + str(error).replace('name ', 'variable ') + '; it was devised automatically but the choice might be incorrect, so test.py might exit immediately after the testing is completed.' - elif os.name == 'nt': - pause = 'pause' - else: - raise NameError, 'configuration ' + str(error).replace('name ', 'variable ') + ' and cannot be devised automatically', sys.exc_info()[2] - - if not dummyinname: - dummyinname = testcaseinname - if not dummyoutname and (not tester or ansname): - dummyoutname = testcaseoutname - - dummyinname = dummyinname.replace('%', taskname) - dummyoutname = dummyoutname.replace('%', taskname) - testcaseinname = testcaseinname.replace('%', taskname) - if not stdio or not options.erase: - inname = inname.replace('%', taskname) - outname = outname.replace('%', taskname) - try: - ansname = ansname.replace('%', taskname) - except NameError: - pass - if tester: - try: inname = inname.replace('%', taskname) - except NameError: pass - outname = outname.replace('%', taskname) - if ansname: - ansname = ansname.replace('%', taskname) - testcaseoutname = testcaseoutname.replace('%', taskname) - else: - testcaseoutname = testcaseoutname.replace('%', taskname) - - if isinstance(padwithzeroestolength, tuple): - padwithzeroestolength, paddummieswithzeroestolength = padwithzeroestolength - else: - paddummieswithzeroestolength = padwithzeroestolength - - if options.python: - dummies = () - s = ' '.join(args) - tests = eval(s) - try: - tests.__iter__ - except AttributeError: - tests = (tests,) - elif len(args): - if os.path.exists(args[0]): - name = args[0] - del args[0] - if len(args) > 1: - dummies = () - tests = args - elif len(args): - dummies = () - s = args[0] - if len(s) < padwithzeroestolength: - s = s.zfill(padwithzeroestolength) - if existstestcase(testcaseinname.replace('$', s)): - tests = (s,) - else: - try: - tests = eval(args[0]) - try: - tests.__iter__ - except AttributeError: - tests = (tests,) - except Exception: - tests = (s,) - - if options.exclude: - testsexcluded = [] - for i in options.exclude: - v = eval(i) - try: - testsexcluded.extend(v) - except TypeError: - testsexcluded.append(v) - - # Windows doesn't like paths beginning with .\ and not ending with an extension - name = os.path.normcase(name) - if os.name == 'nt' and name.startswith('.\\'): - name = name[2:] - - newpointmap = {} - - for i in pointmap: - try: - for j in i: - newpointmap[j] = pointmap[i] - except TypeError: - newpointmap[i] = pointmap[i] - - pointmap = newpointmap - - if not tester: - maxexitcode = 0 - - if maxtime > 0: - strmaxtime = '/%.3f' % maxtime - else: - strmaxtime = '' - - padoutputtolength = 0 - ntests = [] - - for j in dummies: - try: - j.__iter__ - except AttributeError: - j = (j,) - ntests.append((j, True)) - for i in j: - s = str(i) - if len(s) < paddummieswithzeroestolength: - s = s.zfill(paddummieswithzeroestolength) - s = 'sample ' + s - if padoutputtolength < len(s): - padoutputtolength = len(s) - - for j in tests: - try: - j.__iter__ - except AttributeError: - j = (j,) - ntests.append((j, False)) - for i in j: - s = str(i) - if len(s) < padwithzeroestolength: - s = s.zfill(padwithzeroestolength) - if padoutputtolength < len(s): - padoutputtolength = len(s) - - tests = ntests - score = maxpoints = ncorrect = ntotal = ncorrectvalued = nvalued = 0 - - if options.copyonly: - j, isdummy = tests[-1] - if isdummy: - realinname = dummyinname - realoutname = dummyoutname - else: - realinname = testcaseinname - realoutname = testcaseoutname - for i in j: - if i in testsexcluded and not isdummy: - continue - s = str(i) - if isdummy: - if len(s) < paddummieswithzeroestolength: - s = s.zfill(paddummieswithzeroestolength) - else: - if len(s) < padwithzeroestolength: - s = s.zfill(padwithzeroestolength) - copytestcase(realinname.replace('$', s), inname) - if ansname: - copytestcase(realoutname.replace('$', s), ansname) - continue - - for j, isdummy in tests: - ncorrectgrp = 0 - ntotalgrp = 0 - scoregrp = 0 - maxpointsgrp = 0 - if isdummy: - realinname = dummyinname - realoutname = dummyoutname - else: - realinname = testcaseinname - realoutname = testcaseoutname - for i in j: - if i in testsexcluded and not isdummy: - continue - ntotalgrp += 1 - s = str(i) - if isdummy: - npoints = 0 - if len(s) < paddummieswithzeroestolength: - s = s.zfill(paddummieswithzeroestolength) - spref = 'sample ' - else: - npoints = pointmap.get(None, maxexitcode if maxexitcode and isinstance(maxexitcode, int) else 1) - npoints = pointmap.get(i, npoints) - maxpointsgrp += npoints - if npoints: - nvalued += 1 - if len(s) < padwithzeroestolength: - s = s.zfill(padwithzeroestolength) - spref = '' - print ' ' * (padoutputtolength - len(spref + s)) + spref + s + ':', - sys.stdout.flush() - outputdata = open(os.devnull, 'w') - if stdio: - f = tempfile.NamedTemporaryFile(delete=False) - inputdatafname = f.name - f.close() - copytestcase(realinname.replace('$', s), inputdatafname) - inputdata = open(inputdatafname, 'rU') - if options.erase: - tempoutput = tempfile.TemporaryFile('w+') - else: - tempoutput = open(outname, 'w+') - try: - proc = subprocess.Popen(name, stdin=inputdata, stdout=tempoutput, stderr=outputdata, universal_newlines=True) - except OSError, error: - raise OSError, 'The program to be tested cannot be launched: ' + str(error), sys.exc_info()[2] - else: - if os.path.exists(outname): - os.remove(outname) - copytestcase(realinname.replace('$', s), inname) - try: - proc = subprocess.Popen(name, stdin=outputdata, stdout=outputdata, stderr=outputdata, universal_newlines=True) - except OSError, error: - raise OSError, 'The program to be tested cannot be launched: ' + str(error), sys.exc_info()[2] - cl = clock() - if maxtime > 0: - while 1: - proc.poll() - elapsed = clock() - cl - if proc.returncode == None: - if elapsed >= maxtime: - print '%.3f%s s, 0/%d, time limit exceeded' % (elapsed, strmaxtime, npoints) - sys.stdout.flush() - while proc.returncode == None: - try: - proc.terminate() - except OSError: - pass - except AttributeError: - try: - os.kill(proc.pid, signal.SIGTERM) - except Exception: - pass - proc.poll() - outputdata.close() - if stdio: - tempoutput.close() - break - else: - print '%.3f%s s,' % (elapsed, strmaxtime), - sys.stdout.flush() - elapsed = 0 - if stdio: - tempoutput.seek(0) - lines = tempoutput.readlines() - tempoutput.close() - break - if elapsed >= maxtime: - continue - else: - data = proc.communicate() - elapsed = clock() - cl - print '%.3f%s s,' % (elapsed, strmaxtime), - sys.stdout.flush() - if stdio: - tempoutput.seek(0) - lines = tempoutput.readlines() - tempoutput.close() - outputdata.close() - if stdio: - inputdata.close() - try: - os.unlink(inputdatafname) - except Exception: - pass - if proc.returncode > 0: - print '0/%d, non-zero return code %d' % (npoints, proc.returncode) - sys.stdout.flush() - elif proc.returncode < 0: - print '0/%d, terminated by signal %d' % (npoints, -proc.returncode) - sys.stdout.flush() - else: - if not tester: - if stdio: - outputdata = opentestcase(realoutname.replace('$', s)) - r = 0 - data = outputdata.read().splitlines(True) - if len(lines) != len(data): - r = 1 - else: - for i in zip(lines, data): - if i[0] != i[1]: - r = 1 - break - outputdata.close() - else: - try: - inputdata = open(outname, 'rU') - except IOError: - print '0/%g, output file not created or not readable' % npoints - sys.stdout.flush() - r = None - else: - outputdata = opentestcase(realoutname.replace('$', s)) - r = 0 - lines = inputdata.readlines() - data = outputdata.read().splitlines(True) - if len(lines) != len(data): - r = 1 - else: - for i in zip(lines, data): - if i[0] != i[1]: - r = 1 - break - inputdata.close() - outputdata.close() - else: - if ansname: - copytestcase(realoutname.replace('$', s), ansname) - if stdio: - try: copytestcase(realinname.replace('$', s), inname) - except NameError: pass - outputdata = open(outname, 'w') - outputdata.writelines(lines) - outputdata.close() - try: - proc = subprocess.Popen(tester, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) - except OSError, error: - raise OSError, 'The tester application cannot be launched: ' + str(error), sys.exc_info()[2] - data = proc.communicate() - r = proc.returncode - if tester and data[0]: - data = ''.join((' (', data[0].strip(), ')')) - else: - data = '' - if not maxexitcode and r or maxexitcode and not r: - print '0/%g, wrong answer%s' % (npoints, data) - sys.stdout.flush() - elif not maxexitcode and r == 0 or maxexitcode and r >= maxexitcode: - print '%g/%g, OK%s' % (npoints, npoints, data) - sys.stdout.flush() - scoregrp += npoints - ncorrectgrp += 1 - if npoints: - ncorrectvalued += 1 - elif maxexitcode and r != None: - actualpoints = npoints*r/maxexitcode if not npoints*r%maxexitcode else float(npoints*r)/maxexitcode - print '%g/%g, partly OK%s' % (actualpoints, npoints, data) - sys.stdout.flush() - scoregrp += actualpoints - ncorrectgrp += 1 - if npoints: - ncorrectvalued += 1 - if ntotalgrp: - if ncorrectgrp < ntotalgrp: - scoregrp = 0 - if ntotalgrp > 1: - print 'Group total: %d/%d tests; %g/%g points' % (ncorrectgrp, ntotalgrp, scoregrp, maxpointsgrp) - sys.stdout.flush() - ncorrect += ncorrectgrp - ntotal += ntotalgrp - score += scoregrp - maxpoints += maxpointsgrp - - if options.erase: - if not stdio or tester: - if os.path.exists(inname): os.remove(inname) - if os.path.exists(outname): os.remove(outname) - if tester and ansname: - if os.path.exists(ansname): os.remove(ansname) - elif stdio: - copytestcase(realinname.replace('$', s), inname) - copytestcase(realoutname.replace('$', s), ansname) - actualpoints = (score*taskweight/maxpoints if not score*taskweight%maxpoints else float(score*taskweight)/maxpoints) if maxpoints else 0 - if nvalued != ntotal: - print 'Grand total: %d/%d tests (%d/%d valued); %g/%g points; weighted score: %g/%g' % (ncorrect, ntotal, ncorrectvalued, nvalued, score, maxpoints, actualpoints, taskweight) - else: - print 'Grand total: %d/%d tests; %g/%g points; weighted score: %g/%g' % (ncorrect, ntotal, score, maxpoints, actualpoints, taskweight) - - scoresumoveralltasks += actualpoints - scoremaxoveralltasks += taskweight - ntasks += 1 - nfulltasks += int((score == maxpoints) if maxpoints else (taskweight == 0)) - - os.chdir(oldcwd) - -if options.clean or options.copyonly: - sys.exit() - -if ntasks != 1: - print - print 'Grand grand total: %g/%g weighted points; %d/%d problems solved fully' % (scoresumoveralltasks, scoremaxoveralltasks, nfulltasks, ntasks) - -if options.pause: - print 'Press any key to exit... ', - sys.stdout.flush() - os.system(pause + ' >' + os.devnull) diff -r e92e6d4aa2ef -r 5afefe51dcdc test-vcs.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-vcs.py Sun Dec 19 19:34:20 2010 +0200 @@ -0,0 +1,969 @@ +#! /usr/bin/python +# Copyright (c) 2009-2010 Chortos-2 + +import os, sys, shutil, time, subprocess, filecmp, optparse, signal, tempfile, tarfile, zipfile + +version = '1.21.0 ($$REV$$)' +parser = optparse.OptionParser(version='test.py '+version, usage='usage: %prog [options] [problem names] [[path' + os.path.sep + 'to' + os.path.sep + ']solution-app] [test case numbers]\n\nTest case numbers can be specified in plain text or as a Python expression\nif there is only one positional argument.\n\nOnly problem names listed in testconf.py are recognized.') +parser.add_option('-u', '--update', dest='update', action='store_true', default=False, help='check for an updated version of test.py') +parser.add_option('-e', '--exclude', dest='exclude', action='append', help='test case number(s) to exclude, as a Python expression; multiple -e options can be supplied') +parser.add_option('-c', '--cleanup', dest='clean', action='store_true', default=False, help='delete the copies of input/output files and exit') +parser.add_option('-s', '--save-io', dest='erase', action='store_false', default=True, help='do not delete the copies of input/output files after the last test case; create copies of input files and store output in files even if the solution uses standard I/O; delete the stored input/output files if the solution uses standard I/O and the -c/--cleanup option is specified') +parser.add_option('-m', '--copy-io', dest='copyonly', action='store_true', default=False, help='only create a copy of the input/output files of the last test case for manual testing; to delete them, use options -cs or -cm') +parser.add_option('-x', '--auto-exit', dest='pause', action='store_false', default=True, help='do not wait for a key to be pressed when finished testing') +parser.add_option('-p', '--python', action='store_true', default=False, help='always parse all positional arguments as a single Python expression (including the first argument even if it names an executable file)') +parser.add_option('-t', '--detect-time', dest='autotime', action='store_true', default=False, help='spend a second detecting the most precise time measurement function') +parser.add_option('-b', dest='builtin', action='store_true', default=False) + +options, args = parser.parse_args() +parser.destroy() +del parser + +if options.builtin: + try: + if args[0] == 'run': + import resource + maxmemory = int(args[1]) + resource.setrlimit(resource.RLIMIT_AS, (maxmemory*1024**2, maxmemory*1024**2)) + os.execv(args[2], args[2:]) + else: + sys.exit(2) + except: + sys.exit(2) + +def update(): + import urllib + latesttext = urllib.urlopen('http://chortos.selfip.net/~astiob/test.py/version.txt').read() + latest = latesttext.split('.') + installed = version.split('.') + update = '' + if latest[0] > installed[0]: + update = 'major' + elif latest[0] == installed[0]: + if latest[1] > installed[1]: + update = 'feature' + elif latest[1] == installed[1]: + if latest[2] > installed[2]: + update = 'bug-fixing' + elif latest[2] == installed[2]: + print 'You are using the latest publicly available version of test.py.' + return + if update == '': + print 'Your copy of test.py is newer than the publicly available version.' + return + print 'A ' + update + ' update to test.py is available. Downloading...' + sys.stdout.flush() + urllib.urlretrieve('http://chortos.selfip.net/~astiob/test.py/test.py', 'test.py') + print 'Downloaded and installed. Now you are using test.py ' + latesttext + '.' + +if options.update: + update() + sys.exit() + +try: + import resource + memlimit = True + def call(name): + pid = os.fork() + if not pid: + resource.setrlimit(resource.RLIMIT_AS, (maxmemory*1024**2, maxmemory*1024**2)) + os.execl(name) + else: + return pid +except ImportError: + memlimit = False + +globals1 = set(globals()) + +# Initialize some configuration variables with default values +tasknames = (os.path.curdir,) +maxtime = 0 +tests = () +dummies = () +testsexcluded = () +padwithzeroestolength = 0 +taskweight = 100 +pointmap = {} +stdio = False +dummyinname = '' +dummyoutname = '' +tester = '' +maxexitcode = 0 + +def exectestconf_helper(name): + if os.path.isfile('tests.tar'): + f = tarfile.open('tests.tar') + try: + exec f.extractfile(name).read() in globals() + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.zip'): + f = zipfile.ZipFile('tests.zip') + try: + exec f.open(name, 'rU').read() in globals() + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.tgz'): + f = tarfile.open('tests.tgz') + try: + exec f.extractfile(name).read() in globals() + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.tar.gz'): + f = tarfile.open('tests.tar.gz') + try: + exec f.extractfile(name).read() in globals() + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.tbz2'): + f = tarfile.open('tests.tbz2') + try: + exec f.extractfile(name).read() in globals() + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.tar.bz2'): + f = tarfile.open('tests.tar.bz2') + try: + exec f.extractfile(name).read() in globals() + f.close() + return True + except KeyError: + f.close() + return False + +try: + execfile('testconf.py') +except IOError, error: + exc_info = sys.exc_info()[2] + try: + execfile(os.path.join('tests', 'testconf.py')) + except IOError: + if not exectestconf_helper('testconf.py'): + raise IOError, (error.errno, 'The configuration file is missing', error.filename), exc_info + del exc_info + +globals2 = set(globals()) +globals2.remove('globals1') +globals2 -= globals1 +del globals1 + +shared = {} +g = globals() +for k in globals2: + shared[k] = g[k] + +newtasknames = [] +while len(args) and args[0] in tasknames: + newtasknames.append(args[0]) + del args[0] +if len(newtasknames): + tasknames = newtasknames + +scoresumoveralltasks = 0 +scoremaxoveralltasks = 0 +ntasks = 0 +nfulltasks = 0 +cwd = '' # At any time this is either '' or taskname + +if options.autotime: + c = time.clock() + time.sleep(1) + c = time.clock() - c + if int(c + .99999) == 1: + clock = time.clock + else: + clock = time.time +elif os.name == 'nt': + clock = time.clock +else: + clock = time.time + +if options.copyonly: + options.erase = False + +def existstestcase_helper(name): + if os.path.isfile('tests.tar'): + f = tarfile.open('tests.tar') + try: + f.getmember(name) + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.zip'): + f = zipfile.ZipFile('tests.zip') + try: + f.getinfo(name) + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.tgz'): + f = tarfile.open('tests.tgz') + try: + f.getmember(name) + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.tar.gz'): + f = tarfile.open('tests.tar.gz') + try: + f.getmember(name) + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.tbz2'): + f = tarfile.open('tests.tbz2') + try: + f.getmember(name) + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.tar.bz2'): + f = tarfile.open('tests.tar.bz2') + try: + f.getmember(name) + f.close() + return True + except KeyError: + f.close() + return False + +def existstestcase(name): + if os.path.isfile(os.path.join('tests', taskname, name)) or os.path.isfile(os.path.join('tests', name)): + return True + if cwd and (os.path.isfile(os.path.join(oldcwd, 'tests', cwd, name)) or os.path.isfile(os.path.join(oldcwd, 'tests', name))): + return True + if existstestcase_helper(os.path.join(taskname, name)) or existstestcase_helper(name): + return True + if cwd: + os.chdir(oldcwd) + if existstestcase_helper(os.path.join(cwd, name)) or existstestcase_helper(name): + os.chdir(cwd) + return True + os.chdir(cwd) + return False + +def opentestcase_helper(name): + if os.path.isfile('tests.tar'): + f = tarfile.open('tests.tar') + try: + c = f.extractfile(name) + return c + except KeyError: + f.close() + if os.path.isfile('tests.zip'): + f = zipfile.ZipFile('tests.zip') + try: + c = f.open(name, 'rU') + f.close() + return c + except KeyError: + f.close() + if os.path.isfile('tests.tgz'): + f = tarfile.open('tests.tgz') + try: + c = f.extractfile(name) + return c + except KeyError: + f.close() + if os.path.isfile('tests.tar.gz'): + f = tarfile.open('tests.tar.gz') + try: + c = f.extractfile(name) + return c + except KeyError: + f.close() + if os.path.isfile('tests.tbz2'): + f = tarfile.open('tests.tbz2') + try: + c = f.extractfile(name) + return c + except KeyError: + f.close() + if os.path.isfile('tests.tar.bz2'): + f = tarfile.open('tests.tar.bz2') + try: + c = f.extractfile(name) + return c + except KeyError: + f.close() + return None + +def opentestcase(name): + if os.path.isfile(os.path.join('tests', taskname, name)): + return open(os.path.join('tests', taskname, name), 'rU') + elif os.path.isfile(os.path.join('tests', name)): + return open(os.path.join('tests', name), 'rU') + f = opentestcase_helper(os.path.join(taskname, name)) + if not f: + f = opentestcase_helper(name) + if f: + return f + if cwd: + if os.path.isfile(os.path.join(oldcwd, 'tests', cwd, name)): + return open(os.path.join(oldcwd, 'tests', cwd, name), 'rU') + elif os.path.isfile(os.path.join(oldcwd, 'tests', name)): + return open(os.path.join(oldcwd, 'tests', name), 'rU') + os.chdir(oldcwd) + f = opentestcase_helper(os.path.join(cwd, name)) + if not f: + f = opentestcase_helper(name) + os.chdir(cwd) + if f: + return f + raise KeyError, 'The test-case-defining file \'' + name + '\' cannot be found' + +def copytestcase_helper(name, target): + if os.path.isfile('tests.tar'): + f = tarfile.open('tests.tar') + try: + m = f.getmember(name) + m.name = target + f.extract(m) + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.zip'): + if not os.path.isabs(target): + f = zipfile.ZipFile('tests.zip') + try: + m = f.getinfo(name) + m.filename = target + f.extract(m) + f.close() + return True + except KeyError: + f.close() + else: + oldcwd = os.getcwdu() + os.chdir('/') # FIXME: portability? + f = zipfile.ZipFile(os.path.join(oldcwd, 'tests.zip')) + try: + m = f.getinfo(name) + m.filename = os.path.relpath(target) + f.extract(m) + f.close() + os.chdir(oldcwd) + return True + except KeyError: + f.close() + os.chdir(oldcwd) + if os.path.isfile('tests.tgz'): + f = tarfile.open('tests.tgz') + try: + m = f.getmember(name) + m.name = target + f.extract(m) + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.tar.gz'): + f = tarfile.open('tests.tar.gz') + try: + m = f.getmember(name) + m.name = target + f.extract(m) + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.tbz2'): + f = tarfile.open('tests.tbz2') + try: + m = f.getmember(name) + m.name = target + f.extract(m) + f.close() + return True + except KeyError: + f.close() + if os.path.isfile('tests.tar.bz2'): + f = tarfile.open('tests.tar.bz2') + try: + m = f.getmember(name) + m.name = target + f.extract(m) + f.close() + return True + except KeyError: + f.close() + return False + +def copytestcase(name, target): + if os.path.isfile(os.path.join('tests', taskname, name)): + shutil.copyfile(os.path.join('tests', taskname, name), target) + return + elif os.path.isfile(os.path.join('tests', name)): + shutil.copyfile(os.path.join('tests', name), target) + return + if copytestcase_helper(os.path.join(taskname, name), target) or copytestcase_helper(name, target): + return + if cwd: + if os.path.isfile(os.path.join(oldcwd, 'tests', cwd, name)): + shutil.copyfile(os.path.join(oldcwd, 'tests', cwd, name), target) + return + elif os.path.isfile(os.path.join(oldcwd, 'tests', name)): + shutil.copyfile(os.path.join(oldcwd, 'tests', name), target) + return + os.chdir(oldcwd) + if copytestcase_helper(os.path.join(cwd, name), target) or copytestcase_helper(name, target): + os.chdir(cwd) + return + os.chdir(cwd) + raise KeyError, 'The test-case-defining file \'' + name + '\' cannot be found' + +# Always chdir if the directory exists but use any existing config +def chdir_and_exec_testconf(): + global cwd + cwd = '' + if os.path.isdir(taskname): + os.chdir(taskname) + if taskname != os.path.curdir: + cwd = taskname + try: + execfile('testconf.py', globals()) + return + except IOError: + pass + if not cwd: + if os.path.isfile(os.path.join('tests', taskname, 'testconf.py')): + execfile(os.path.join('tests', taskname, 'testconf.py'), globals()) + return + if os.path.isfile(os.path.join('tests', 'testconf.py')): + execfile(os.path.join('tests', 'testconf.py'), globals()) + return + if exectestconf_helper(os.path.join(taskname, 'testconf.py')) or exectestconf_helper('testconf.py'): + return + if cwd: + os.chdir(oldcwd) + if os.path.isfile(os.path.join('tests', cwd, 'testconf.py')): + execfile(os.path.join('tests', cwd, 'testconf.py'), globals()) + os.chdir(cwd) + return + if os.path.isfile(os.path.join('tests', 'testconf.py')): + execfile(os.path.join('tests', 'testconf.py'), globals()) + os.chdir(cwd) + return + if exectestconf_helper(os.path.join(cwd, 'testconf.py')) or exectestconf_helper('testconf.py'): + os.chdir(cwd) + return + if os.path.isfile('testconf.py'): + execfile('testconf.py', globals()) + os.chdir(cwd) + return + os.chdir(cwd) + elif os.path.isfile('testconf.py'): + execfile('testconf.py', globals()) + return + raise KeyError, 'The configuration file for task ' + taskname + ' is missing' + +try: + name + namedefined = True +except Exception: + namedefined = False + +for taskname in tasknames: + if ntasks: + print + + try: + if len(tasknames) > 1: + print taskname + except Exception: + if taskname != os.path.curdir or ntasks: + print taskname + + try: del inname + except NameError: pass + try: del outname + except NameError: pass + try: del ansname + except NameError: pass + + if not namedefined and taskname != os.path.curdir: + name = os.path.join(os.path.curdir, taskname) + for k in shared: + g[k] = shared[k] + + oldcwd = os.getcwdu() + chdir_and_exec_testconf() + + if options.clean: + try: + if not stdio or tester: + if not tester: + inname + outname + if tester: + ansname + except NameError, error: + raise NameError, 'configuration ' + str(error).replace('name ', 'variable ', 1), sys.exc_info()[2] + if not options.erase: + try: + inname = inname.replace('%', taskname) + except NameError: + inname = taskname + '.in' + try: + outname = outname.replace('%', taskname) + except NameError: + outname = taskname + '.out' + try: + ansname = ansname.replace('%', taskname) + except NameError: + ansname = taskname + '.ans' + elif not stdio or tester or not options.erase: + inname = inname.replace('%', taskname) + outname = outname.replace('%', taskname) + if tester: + ansname = ansname.replace('%', taskname) + if not stdio or tester or not options.erase: + if os.path.exists(inname): os.remove(inname) + if os.path.exists(outname): os.remove(outname) + if (tester or not options.erase) and ansname: + if os.path.exists(ansname): os.remove(ansname) + continue + + try: + name + except NameError, error: + if str(error).count('name') == 1: + raise NameError, 'configuration ' + str(error), sys.exc_info()[2] + else: + raise NameError, 'configuration ' + str(error).replace('name ', 'variable ', 1), sys.exc_info()[2] + + try: + if not stdio: + inname + outname + testcaseinname + if tester: + outname + if ansname: + testcaseoutname + else: + testcaseoutname + except NameError, error: + raise NameError, 'configuration ' + str(error).replace('name ', 'variable ', 1), sys.exc_info()[2] + + if not options.erase: + try: + inname + except NameError: + inname = taskname + '.in' + try: + outname + except NameError: + outname = taskname + '.out' + try: + ansname + except NameError: + ansname = taskname + '.ans' + + if options.pause: + try: + pause + except NameError, error: + if os.name == 'posix': + pause = 'read -s -n 1' + print 'Configuration ' + str(error).replace('name ', 'variable ') + '; it was devised automatically but the choice might be incorrect, so test.py might exit immediately after the testing is completed.' + elif os.name == 'nt': + pause = 'pause' + else: + raise NameError, 'configuration ' + str(error).replace('name ', 'variable ') + ' and cannot be devised automatically', sys.exc_info()[2] + + if not dummyinname: + dummyinname = testcaseinname + if not dummyoutname and (not tester or ansname): + dummyoutname = testcaseoutname + + dummyinname = dummyinname.replace('%', taskname) + dummyoutname = dummyoutname.replace('%', taskname) + testcaseinname = testcaseinname.replace('%', taskname) + if not stdio or not options.erase: + inname = inname.replace('%', taskname) + outname = outname.replace('%', taskname) + try: + ansname = ansname.replace('%', taskname) + except NameError: + pass + if tester: + try: inname = inname.replace('%', taskname) + except NameError: pass + outname = outname.replace('%', taskname) + if ansname: + ansname = ansname.replace('%', taskname) + testcaseoutname = testcaseoutname.replace('%', taskname) + else: + testcaseoutname = testcaseoutname.replace('%', taskname) + + if isinstance(padwithzeroestolength, tuple): + padwithzeroestolength, paddummieswithzeroestolength = padwithzeroestolength + else: + paddummieswithzeroestolength = padwithzeroestolength + + if options.python: + dummies = () + s = ' '.join(args) + tests = eval(s) + try: + tests.__iter__ + except AttributeError: + tests = (tests,) + elif len(args): + if os.path.exists(args[0]): + name = args[0] + del args[0] + if len(args) > 1: + dummies = () + tests = args + elif len(args): + dummies = () + s = args[0] + if len(s) < padwithzeroestolength: + s = s.zfill(padwithzeroestolength) + if existstestcase(testcaseinname.replace('$', s)): + tests = (s,) + else: + try: + tests = eval(args[0]) + try: + tests.__iter__ + except AttributeError: + tests = (tests,) + except Exception: + tests = (s,) + + if options.exclude: + testsexcluded = [] + for i in options.exclude: + v = eval(i) + try: + testsexcluded.extend(v) + except TypeError: + testsexcluded.append(v) + + # Windows doesn't like paths beginning with .\ and not ending with an extension + name = os.path.normcase(name) + if os.name == 'nt' and name.startswith('.\\'): + name = name[2:] + + newpointmap = {} + + for i in pointmap: + try: + for j in i: + newpointmap[j] = pointmap[i] + except TypeError: + newpointmap[i] = pointmap[i] + + pointmap = newpointmap + + if not tester: + maxexitcode = 0 + + if maxtime > 0: + strmaxtime = '/%.3f' % maxtime + else: + strmaxtime = '' + + padoutputtolength = 0 + ntests = [] + + for j in dummies: + try: + j.__iter__ + except AttributeError: + j = (j,) + ntests.append((j, True)) + for i in j: + s = str(i) + if len(s) < paddummieswithzeroestolength: + s = s.zfill(paddummieswithzeroestolength) + s = 'sample ' + s + if padoutputtolength < len(s): + padoutputtolength = len(s) + + for j in tests: + try: + j.__iter__ + except AttributeError: + j = (j,) + ntests.append((j, False)) + for i in j: + s = str(i) + if len(s) < padwithzeroestolength: + s = s.zfill(padwithzeroestolength) + if padoutputtolength < len(s): + padoutputtolength = len(s) + + tests = ntests + score = maxpoints = ncorrect = ntotal = ncorrectvalued = nvalued = 0 + + if options.copyonly: + j, isdummy = tests[-1] + if isdummy: + realinname = dummyinname + realoutname = dummyoutname + else: + realinname = testcaseinname + realoutname = testcaseoutname + for i in j: + if i in testsexcluded and not isdummy: + continue + s = str(i) + if isdummy: + if len(s) < paddummieswithzeroestolength: + s = s.zfill(paddummieswithzeroestolength) + else: + if len(s) < padwithzeroestolength: + s = s.zfill(padwithzeroestolength) + copytestcase(realinname.replace('$', s), inname) + if ansname: + copytestcase(realoutname.replace('$', s), ansname) + continue + + for j, isdummy in tests: + ncorrectgrp = 0 + ntotalgrp = 0 + scoregrp = 0 + maxpointsgrp = 0 + if isdummy: + realinname = dummyinname + realoutname = dummyoutname + else: + realinname = testcaseinname + realoutname = testcaseoutname + for i in j: + if i in testsexcluded and not isdummy: + continue + ntotalgrp += 1 + s = str(i) + if isdummy: + npoints = 0 + if len(s) < paddummieswithzeroestolength: + s = s.zfill(paddummieswithzeroestolength) + spref = 'sample ' + else: + npoints = pointmap.get(None, maxexitcode if maxexitcode and isinstance(maxexitcode, int) else 1) + npoints = pointmap.get(i, npoints) + maxpointsgrp += npoints + if npoints: + nvalued += 1 + if len(s) < padwithzeroestolength: + s = s.zfill(padwithzeroestolength) + spref = '' + print ' ' * (padoutputtolength - len(spref + s)) + spref + s + ':', + sys.stdout.flush() + outputdata = open(os.devnull, 'w') + if stdio: + f = tempfile.NamedTemporaryFile(delete=False) + inputdatafname = f.name + f.close() + copytestcase(realinname.replace('$', s), inputdatafname) + inputdata = open(inputdatafname, 'rU') + if options.erase: + tempoutput = tempfile.TemporaryFile('w+') + else: + tempoutput = open(outname, 'w+') + try: + proc = subprocess.Popen(name, stdin=inputdata, stdout=tempoutput, stderr=outputdata, universal_newlines=True) + except OSError, error: + raise OSError, 'The program to be tested cannot be launched: ' + str(error), sys.exc_info()[2] + else: + if os.path.exists(outname): + os.remove(outname) + copytestcase(realinname.replace('$', s), inname) + try: + proc = subprocess.Popen(name, stdin=outputdata, stdout=outputdata, stderr=outputdata, universal_newlines=True) + except OSError, error: + raise OSError, 'The program to be tested cannot be launched: ' + str(error), sys.exc_info()[2] + cl = clock() + if maxtime > 0: + while 1: + proc.poll() + elapsed = clock() - cl + if proc.returncode == None: + if elapsed >= maxtime: + print '%.3f%s s, 0/%d, time limit exceeded' % (elapsed, strmaxtime, npoints) + sys.stdout.flush() + while proc.returncode == None: + try: + proc.terminate() + except OSError: + pass + except AttributeError: + try: + os.kill(proc.pid, signal.SIGTERM) + except Exception: + pass + proc.poll() + outputdata.close() + if stdio: + tempoutput.close() + break + else: + print '%.3f%s s,' % (elapsed, strmaxtime), + sys.stdout.flush() + elapsed = 0 + if stdio: + tempoutput.seek(0) + lines = tempoutput.readlines() + tempoutput.close() + break + if elapsed >= maxtime: + continue + else: + data = proc.communicate() + elapsed = clock() - cl + print '%.3f%s s,' % (elapsed, strmaxtime), + sys.stdout.flush() + if stdio: + tempoutput.seek(0) + lines = tempoutput.readlines() + tempoutput.close() + outputdata.close() + if stdio: + inputdata.close() + try: + os.unlink(inputdatafname) + except Exception: + pass + if proc.returncode > 0: + print '0/%d, non-zero return code %d' % (npoints, proc.returncode) + sys.stdout.flush() + elif proc.returncode < 0: + print '0/%d, terminated by signal %d' % (npoints, -proc.returncode) + sys.stdout.flush() + else: + if not tester: + if stdio: + outputdata = opentestcase(realoutname.replace('$', s)) + r = 0 + data = outputdata.read().splitlines(True) + if len(lines) != len(data): + r = 1 + else: + for i in zip(lines, data): + if i[0] != i[1]: + r = 1 + break + outputdata.close() + else: + try: + inputdata = open(outname, 'rU') + except IOError: + print '0/%g, output file not created or not readable' % npoints + sys.stdout.flush() + r = None + else: + outputdata = opentestcase(realoutname.replace('$', s)) + r = 0 + lines = inputdata.readlines() + data = outputdata.read().splitlines(True) + if len(lines) != len(data): + r = 1 + else: + for i in zip(lines, data): + if i[0] != i[1]: + r = 1 + break + inputdata.close() + outputdata.close() + else: + if ansname: + copytestcase(realoutname.replace('$', s), ansname) + if stdio: + try: copytestcase(realinname.replace('$', s), inname) + except NameError: pass + outputdata = open(outname, 'w') + outputdata.writelines(lines) + outputdata.close() + try: + proc = subprocess.Popen(tester, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) + except OSError, error: + raise OSError, 'The tester application cannot be launched: ' + str(error), sys.exc_info()[2] + data = proc.communicate() + r = proc.returncode + if tester and data[0]: + data = ''.join((' (', data[0].strip(), ')')) + else: + data = '' + if not maxexitcode and r or maxexitcode and not r: + print '0/%g, wrong answer%s' % (npoints, data) + sys.stdout.flush() + elif not maxexitcode and r == 0 or maxexitcode and r >= maxexitcode: + print '%g/%g, OK%s' % (npoints, npoints, data) + sys.stdout.flush() + scoregrp += npoints + ncorrectgrp += 1 + if npoints: + ncorrectvalued += 1 + elif maxexitcode and r != None: + actualpoints = npoints*r/maxexitcode if not npoints*r%maxexitcode else float(npoints*r)/maxexitcode + print '%g/%g, partly OK%s' % (actualpoints, npoints, data) + sys.stdout.flush() + scoregrp += actualpoints + ncorrectgrp += 1 + if npoints: + ncorrectvalued += 1 + if ntotalgrp: + if ncorrectgrp < ntotalgrp: + scoregrp = 0 + if ntotalgrp > 1: + print 'Group total: %d/%d tests; %g/%g points' % (ncorrectgrp, ntotalgrp, scoregrp, maxpointsgrp) + sys.stdout.flush() + ncorrect += ncorrectgrp + ntotal += ntotalgrp + score += scoregrp + maxpoints += maxpointsgrp + + if options.erase: + if not stdio or tester: + if os.path.exists(inname): os.remove(inname) + if os.path.exists(outname): os.remove(outname) + if tester and ansname: + if os.path.exists(ansname): os.remove(ansname) + elif stdio: + copytestcase(realinname.replace('$', s), inname) + copytestcase(realoutname.replace('$', s), ansname) + actualpoints = (score*taskweight/maxpoints if not score*taskweight%maxpoints else float(score*taskweight)/maxpoints) if maxpoints else 0 + if nvalued != ntotal: + print 'Grand total: %d/%d tests (%d/%d valued); %g/%g points; weighted score: %g/%g' % (ncorrect, ntotal, ncorrectvalued, nvalued, score, maxpoints, actualpoints, taskweight) + else: + print 'Grand total: %d/%d tests; %g/%g points; weighted score: %g/%g' % (ncorrect, ntotal, score, maxpoints, actualpoints, taskweight) + + scoresumoveralltasks += actualpoints + scoremaxoveralltasks += taskweight + ntasks += 1 + nfulltasks += int((score == maxpoints) if maxpoints else (taskweight == 0)) + + os.chdir(oldcwd) + +if options.clean or options.copyonly: + sys.exit() + +if ntasks != 1: + print + print 'Grand grand total: %g/%g weighted points; %d/%d problems solved fully' % (scoresumoveralltasks, scoremaxoveralltasks, nfulltasks, ntasks) + +if options.pause: + print 'Press any key to exit... ', + sys.stdout.flush() + os.system(pause + ' >' + os.devnull)