view upreckon/upreckon-vcs @ 193:a76cdc26ba9d

Added conf. var. match and match='regexp' for non-archives Specify match='regexp', and your tests and dummies will be treated as regular expressions describing test case identifiers. Every file that is in a suitable location and whose name matches {testcase,dummy}inname and the given regexp will be treated as a file with test case input data. You are free to use backreferences in the regexps, but group numbering starts at two rather than one. If you want test groups, you can get them magically created for you by putting a part of the test ID in a group in the regexp sense and specifying the tests variable as a pair consisting of the regexp itself and the number of this regexp group (remember group numbers start at two).
author Oleg Oshmyan <chortos@inbox.lv>
date Thu, 11 Aug 2011 23:20:52 +0300
parents 4df9537ed261
children d46bb4495766
line wrap: on
line source

#! /usr/bin/env python
# Copyright (c) 2009-2011 Chortos-2 <chortos@inbox.lv>

from __future__ import division, with_statement
import optparse

from upreckon import compat
from upreckon.compat import *

version = '2.03.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('-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('--list-problems', action='store_true', default=False, help='just list all problem names')
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('-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')
parser.add_option('-k', '--skim', action='store_true', default=False, help='skip test groups as soon as one test case is failed')
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

from upreckon import config
import itertools, os, subprocess, sys, time

if options.legacy:
	compat.pseudobuiltins += 'xrange',

if options.list_problems:
	options.pause = False

from upreckon import testcases

try:
	from upreckon.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.')
	
	from upreckon.problem import *
	
	# Support single-problem configurations
	if globalconf.problems is None:
		shouldprintnames = False
		globalconf.multiproblem = False
		globalconf.problems = os.path.curdir,
	else:
		globalconf.multiproblem = True
		shouldprintnames = True
	
	if options.list_problems:
		for taskname in globalconf.problems:
			say(taskname)
		sys.exit()
	
	ntasks = 0
	nfulltasks = 0
	maxscore = 0
	realscore = 0
	
	for taskname in (globalconf.problems 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 total: %g/%g weighted points; %d/%d problems solved fully' % (realscore, maxscore, nfulltasks, ntasks))
except KeyboardInterrupt:
	say('Exiting due to a keyboard interrupt.', end='', file=sys.stderr)
	sys.stderr.flush()
	try:
		import signal
		signal.signal(signal.SIGINT, signal.SIG_DFL)
		os.kill(os.getpid(), signal.SIGINT)
	except Exception:
		pass
	# Do this even if we got no exceptions, just in case
	say(file=sys.stderr)
	sys.exit(1)

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, shell=True, stdout=devnull, stderr=subprocess.STDOUT)