#!/usr/bin/env python
#
# Copyright (C) 2010, 2011 MaskRay
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# ------------------------------------------------------------------------------
#
# checker
# check programs using testdata
COPYING = '''checker
Copyright (C) 2010, 2011 MaskRay
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
'''
def rreplace(s1, s2, s3):
p = s1.rfind(s2)
return s1[:p] + s3 + s1[p+len(s2):] if p != -1 else s1
def test(s, pat1, pat2):
p = s.find(pat1)
if p == -1:
return False
q = s.find(pat2)
while q != -1:
if not p <= q < p+len(pat1):
return True
q = s.find(pat2, q+len(pat2))
return False
if __name__ == '__main__':
import math, sys, os, re, subprocess, threading, time, tempfile
from optparse import OptionParser
def main():
def print_copying():
sys.stdout.write(COPYING)
exit(0)
usage = '''usage: %prog source [input] [output]
source - source file
input - suffix of input files (default `in')
output - suffix of output files (default `out')'''
parser = OptionParser(usage=usage)
parser.add_option('-p', '--path', action='store',
dest='path', default='/tmp',
help='specify the path of testdata')
parser.add_option('-i', '--dataid', action='store',
dest='dataid', default='', help='specify the data id')
parser.add_option('-d', '--detail', action='store_true',
dest='show_detail', default=False, help='show details')
parser.add_option('-s', '--showtime', action='store_true',
dest='show_time', default=False, help='show time used')
parser.add_option('-t', '--time-limit', action='store', type='float',
dest='time_limit', default=1.)
parser.add_option('--version', action="callback",
callback=lambda o, s, v, p: print_copying(),
help="print the COPYING and exit")
(options, args) = parser.parse_args()
options.path = os.path.expanduser(options.path)
if len(args) < 1 or len(args) > 4:
parser.print_usage()
sys.exit(1)
if len(args) < 2:
args.append('in')
if len(args) < 3:
args.append('out')
r = re.compile('\d+')
L = [file for file in os.listdir(options.path) if test(file, args[0], args[1])]
for file in sorted(L, key = lambda x: int(r.findall(x)[-1] if
r.findall(x) else sys.maxint)):
if options.dataid != '' and (not r.findall(file) or
r.findall(file)[-1] != options.dataid):
continue
print('---' + file + '---')
temp = tempfile.NamedTemporaryFile()
sub = subprocess.Popen('./main', stdin=open(os.path.join(options.path, file)), stdout=temp)
bgn = time.time()
timer = threading.Timer(options.time_limit, sub.terminate)
timer.start()
ret = sub.wait()
end = time.time()
timer.cancel()
RESET = '\033[0m'
if ret == -11:
print('\033[1;34m' + 'runtime error' + RESET)
elif ret == -15:
print('\033[1;35m' + 'time limit exceed' + RESET)
elif ret == 0:
sys.stdout.write('\033[1m')
sys.stdout.flush()
with open(os.path.join(options.path, rreplace(file, args[1], args[2]))) as f:
lines = f.readlines()
if len(lines) == 1 and re.search('''\d+\.\d+''', lines[0]):
res = float(lines[0])
with open(temp.name) as f:
lines = f.readlines()
if len(lines) != 1:
print('wrong answer' + RESET)
elif math.isnan(float(lines[0])) or abs(float(lines[0])-res) > 1e-9:
print('< %f\n---\n> %f\n' % (res, float(lines[0])) + RESET)
elif 0 == os.system('diff --strip-trailing-cr %s %s %s' %
('' if options.show_detail else '-q',
os.path.join(options.path, rreplace(file, args[1], args[2])),
temp.name)) and options.show_time:
print(RESET + '%.3f second(s)' % (end-bgn))
else:
sys.stdout.write(RESET)
sys.stdout.flush()
else:
print('\033[1;32m' + 'exit abnormally' + RESET)
main()