comparison test.py @ 49:245150080c48 1.20 1.20.3

Converted 1.20 into a branch
author Oleg Oshmyan <chortos@inbox.lv>
date Sun, 19 Dec 2010 23:23:24 +0200
parents 1.20/test.py@5bfa23cd638d
children
comparison
equal deleted inserted replaced
47:06f1683c8db9 49:245150080c48
1 #! /usr/bin/python
2 # Copyright (c) 2009, 2010 Chortos-2 <chortos@inbox.lv>
3
4 import os, sys, shutil, time, subprocess, filecmp, optparse, signal, tempfile, tarfile, zipfile
5
6 parser = optparse.OptionParser(version='test.py 1.20.3', usage='usage: %prog [options] [problem names] [[path/to/]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.')
7 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')
8 parser.add_option('-c', '--cleanup', dest='clean', action='store_true', default=False, help='delete the copies of input/output files and exit')
9 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')
10 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')
11 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')
12 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)')
13 parser.add_option('-t', '--detect-time', dest='autotime', action='store_true', default=False, help='spend a second detecting the most precise time measurement function')
14
15 options, args = parser.parse_args()
16 parser.destroy()
17 del parser
18
19 globals1 = set(globals())
20
21 # Initialize some configuration variables with default values
22 tasknames = ('.',)
23 maxtime = 0
24 tests = ()
25 dummies = ()
26 testsexcluded = ()
27 padwithzeroestolength = 0
28 taskweight = 100
29 pointmap = {}
30 stdio = False
31 dummyinname = ''
32 dummyoutname = ''
33 tester = ''
34
35 def exectestconf_helper(name):
36 if os.path.isfile('tests.tar'):
37 f = tarfile.open('tests.tar')
38 try:
39 exec f.extractfile(name).read() in globals()
40 f.close()
41 return True
42 except KeyError:
43 f.close()
44 if os.path.isfile('tests.zip'):
45 f = zipfile.ZipFile('tests.zip')
46 try:
47 exec f.open(name, 'rU').read() in globals()
48 f.close()
49 return True
50 except KeyError:
51 f.close()
52 if os.path.isfile('tests.tgz'):
53 f = tarfile.open('tests.tgz')
54 try:
55 exec f.extractfile(name).read() in globals()
56 f.close()
57 return True
58 except KeyError:
59 f.close()
60 if os.path.isfile('tests.tar.gz'):
61 f = tarfile.open('tests.tar.gz')
62 try:
63 exec f.extractfile(name).read() in globals()
64 f.close()
65 return True
66 except KeyError:
67 f.close()
68 if os.path.isfile('tests.tbz2'):
69 f = tarfile.open('tests.tbz2')
70 try:
71 exec f.extractfile(name).read() in globals()
72 f.close()
73 return True
74 except KeyError:
75 f.close()
76 if os.path.isfile('tests.tar.bz2'):
77 f = tarfile.open('tests.tar.bz2')
78 try:
79 exec f.extractfile(name).read() in globals()
80 f.close()
81 return True
82 except KeyError:
83 f.close()
84 return False
85
86 try:
87 execfile('testconf.py')
88 except IOError, error:
89 exc_info = sys.exc_info()[2]
90 try:
91 execfile('tests/testconf.py')
92 except IOError:
93 if not exectestconf_helper('testconf.py'):
94 raise IOError, (error.errno, 'The configuration file is missing', error.filename), exc_info
95 del exc_info
96
97 globals2 = set(globals())
98 globals2.remove('globals1')
99 globals2 -= globals1
100 del globals1
101
102 shared = {}
103 g = globals()
104 for k in globals2:
105 shared[k] = g[k]
106
107 newtasknames = []
108 while len(args) and args[0] in tasknames:
109 newtasknames.append(args[0])
110 del args[0]
111 if len(newtasknames):
112 tasknames = newtasknames
113
114 scoresumoveralltasks = 0
115 scoremaxoveralltasks = 0
116 ntasks = 0
117 nfulltasks = 0
118 cwd = '' # At any time this is either '' or taskname + '/'
119
120 if options.autotime:
121 c = time.clock()
122 time.sleep(1)
123 c = time.clock() - c
124 if int(c + .99999) == 1:
125 clock = time.clock
126 else:
127 clock = time.time
128 elif os.name == 'nt':
129 clock = time.clock
130 else:
131 clock = time.time
132
133 if options.copyonly:
134 options.erase = False
135
136 def existstestcase_helper(name):
137 if os.path.isfile('tests.tar'):
138 f = tarfile.open('tests.tar')
139 try:
140 f.getmember(name)
141 f.close()
142 return True
143 except KeyError:
144 f.close()
145 if os.path.isfile('tests.zip'):
146 f = zipfile.ZipFile('tests.zip')
147 try:
148 f.getinfo(name)
149 f.close()
150 return True
151 except KeyError:
152 f.close()
153 if os.path.isfile('tests.tgz'):
154 f = tarfile.open('tests.tgz')
155 try:
156 f.getmember(name)
157 f.close()
158 return True
159 except KeyError:
160 f.close()
161 if os.path.isfile('tests.tar.gz'):
162 f = tarfile.open('tests.tar.gz')
163 try:
164 f.getmember(name)
165 f.close()
166 return True
167 except KeyError:
168 f.close()
169 if os.path.isfile('tests.tbz2'):
170 f = tarfile.open('tests.tbz2')
171 try:
172 f.getmember(name)
173 f.close()
174 return True
175 except KeyError:
176 f.close()
177 if os.path.isfile('tests.tar.bz2'):
178 f = tarfile.open('tests.tar.bz2')
179 try:
180 f.getmember(name)
181 f.close()
182 return True
183 except KeyError:
184 f.close()
185 return False
186
187 def existstestcase(name):
188 if os.path.isfile('tests/' + taskname + '/' + name) or os.path.isfile('tests/' + name):
189 return True
190 if cwd and (os.path.isfile(oldcwd + '/tests/' + cwd + name) or os.path.isfile(oldcwd + '/tests/' + name)):
191 return True
192 if existstestcase_helper(taskname + '/' + name) or existstestcase_helper(name):
193 return True
194 if cwd:
195 os.chdir(oldcwd)
196 if existstestcase_helper(cwd + name) or existstestcase_helper(name):
197 os.chdir(cwd)
198 return True
199 os.chdir(cwd)
200 return False
201
202 def opentestcase_helper(name):
203 if os.path.isfile('tests.tar'):
204 f = tarfile.open('tests.tar')
205 try:
206 c = f.extractfile(name)
207 return c
208 except KeyError:
209 f.close()
210 if os.path.isfile('tests.zip'):
211 f = zipfile.ZipFile('tests.zip')
212 try:
213 c = f.open(name, 'rU')
214 f.close()
215 return c
216 except KeyError:
217 f.close()
218 if os.path.isfile('tests.tgz'):
219 f = tarfile.open('tests.tgz')
220 try:
221 c = f.extractfile(name)
222 return c
223 except KeyError:
224 f.close()
225 if os.path.isfile('tests.tar.gz'):
226 f = tarfile.open('tests.tar.gz')
227 try:
228 c = f.extractfile(name)
229 return c
230 except KeyError:
231 f.close()
232 if os.path.isfile('tests.tbz2'):
233 f = tarfile.open('tests.tbz2')
234 try:
235 c = f.extractfile(name)
236 return c
237 except KeyError:
238 f.close()
239 if os.path.isfile('tests.tar.bz2'):
240 f = tarfile.open('tests.tar.bz2')
241 try:
242 c = f.extractfile(name)
243 return c
244 except KeyError:
245 f.close()
246 return None
247
248 def opentestcase(name):
249 if os.path.isfile('tests/' + taskname + '/' + name):
250 return open('tests/' + taskname + '/' + name, 'rU')
251 elif os.path.isfile('tests/' + name):
252 return open('tests/' + name, 'rU')
253 f = opentestcase_helper(taskname + '/' + name)
254 if not f:
255 f = opentestcase_helper(name)
256 if f:
257 return f
258 if cwd:
259 if os.path.isfile(oldcwd + '/tests/' + cwd + name):
260 return open(oldcwd + '/tests/' + cwd + name, 'rU')
261 elif os.path.isfile(oldcwd + '/tests/' + name):
262 return open(oldcwd + '/tests/' + name, 'rU')
263 os.chdir(oldcwd)
264 f = opentestcase_helper(cwd + name)
265 if not f:
266 f = opentestcase_helper(name)
267 os.chdir(cwd)
268 if f:
269 return f
270 raise KeyError, 'The test-case-defining file \'' + name + '\' cannot be found'
271
272 def copytestcase_helper(name, target):
273 if os.path.isfile('tests.tar'):
274 f = tarfile.open('tests.tar')
275 try:
276 m = f.getmember(name)
277 m.name = target
278 f.extract(m)
279 f.close()
280 return True
281 except KeyError:
282 f.close()
283 if os.path.isfile('tests.zip'):
284 if not target.startswith('/'):
285 f = zipfile.ZipFile('tests.zip')
286 try:
287 m = f.getinfo(name)
288 m.filename = target
289 f.extract(m)
290 f.close()
291 return True
292 except KeyError:
293 f.close()
294 else:
295 oldcwd = os.getcwdu()
296 os.chdir('/')
297 f = zipfile.ZipFile(oldcwd + '/tests.zip')
298 try:
299 m = f.getinfo(name)
300 m.filename = os.path.relpath(target)
301 f.extract(m)
302 f.close()
303 os.chdir(oldcwd)
304 return True
305 except KeyError:
306 f.close()
307 os.chdir(oldcwd)
308 if os.path.isfile('tests.tgz'):
309 f = tarfile.open('tests.tgz')
310 try:
311 m = f.getmember(name)
312 m.name = target
313 f.extract(m)
314 f.close()
315 return True
316 except KeyError:
317 f.close()
318 if os.path.isfile('tests.tar.gz'):
319 f = tarfile.open('tests.tar.gz')
320 try:
321 m = f.getmember(name)
322 m.name = target
323 f.extract(m)
324 f.close()
325 return True
326 except KeyError:
327 f.close()
328 if os.path.isfile('tests.tbz2'):
329 f = tarfile.open('tests.tbz2')
330 try:
331 m = f.getmember(name)
332 m.name = target
333 f.extract(m)
334 f.close()
335 return True
336 except KeyError:
337 f.close()
338 if os.path.isfile('tests.tar.bz2'):
339 f = tarfile.open('tests.tar.bz2')
340 try:
341 m = f.getmember(name)
342 m.name = target
343 f.extract(m)
344 f.close()
345 return True
346 except KeyError:
347 f.close()
348 return False
349
350 def copytestcase(name, target):
351 if os.path.isfile('tests/' + taskname + '/' + name):
352 shutil.copyfile('tests/' + taskname + '/' + name, target)
353 return
354 elif os.path.isfile('tests/' + name):
355 shutil.copyfile('tests/' + name, target)
356 return
357 if copytestcase_helper(taskname + '/' + name, target) or copytestcase_helper(name, target):
358 return
359 if cwd:
360 if os.path.isfile(oldcwd + '/tests/' + cwd + name):
361 shutil.copyfile(oldcwd + '/tests/' + cwd + name, target)
362 return
363 elif os.path.isfile(oldcwd + '/tests/' + name):
364 shutil.copyfile(oldcwd + '/tests/' + name, target)
365 return
366 os.chdir(oldcwd)
367 if copytestcase_helper(cwd + name, target) or copytestcase_helper(name, target):
368 os.chdir(cwd)
369 return
370 os.chdir(cwd)
371 raise KeyError, 'The test-case-defining file \'' + name + '\' cannot be found'
372
373 # Always chdir if the directory exists but use any existing config
374 def chdir_and_exec_testconf():
375 global cwd
376 cwd = ''
377 if os.path.isdir(taskname):
378 os.chdir(taskname)
379 if taskname != '.':
380 cwd = taskname + '/'
381 try:
382 execfile('testconf.py', globals())
383 return
384 except IOError:
385 pass
386 if not cwd:
387 if os.path.isfile('tests/' + taskname + '/testconf.py'):
388 execfile('tests/' + taskname + '/testconf.py', globals())
389 return
390 if os.path.isfile('tests/testconf.py'):
391 execfile('tests/testconf.py', globals())
392 return
393 if exectestconf_helper(taskname + '/testconf.py') or exectestconf_helper('testconf.py'):
394 return
395 if cwd:
396 os.chdir(oldcwd)
397 if os.path.isfile('tests/' + cwd + 'testconf.py'):
398 execfile('tests/' + cwd + 'testconf.py', globals())
399 os.chdir(cwd)
400 return
401 if os.path.isfile('tests/testconf.py'):
402 execfile('tests/testconf.py', globals())
403 os.chdir(cwd)
404 return
405 if exectestconf_helper(cwd + 'testconf.py') or exectestconf_helper('testconf.py'):
406 os.chdir(cwd)
407 return
408 if os.path.isfile('testconf.py'):
409 execfile('testconf.py', globals())
410 os.chdir(cwd)
411 return
412 os.chdir(cwd)
413 elif os.path.isfile('testconf.py'):
414 execfile('testconf.py', globals())
415 return
416 raise KeyError, 'The configuration file for task ' + taskname + ' is missing'
417
418 try:
419 name
420 namedefined = True
421 except Exception:
422 namedefined = False
423
424 for taskname in tasknames:
425 if ntasks:
426 print
427
428 try:
429 if len(tasknames) > 1:
430 print taskname
431 except Exception:
432 if taskname != '.' or ntasks:
433 print taskname
434
435 try: del inname
436 except NameError: pass
437 try: del outname
438 except NameError: pass
439 try: del ansname
440 except NameError: pass
441
442 if not namedefined and taskname != '.':
443 name = './' + taskname
444 for k in shared:
445 g[k] = shared[k]
446
447 oldcwd = os.getcwdu()
448 chdir_and_exec_testconf()
449
450 if options.clean:
451 try:
452 if not stdio or tester:
453 if not tester:
454 inname
455 outname
456 if tester:
457 ansname
458 except NameError, error:
459 raise NameError, 'configuration ' + str(error).replace('name ', 'variable ', 1), sys.exc_info()[2]
460 if not options.erase:
461 try:
462 inname = inname.replace('%', taskname)
463 except NameError:
464 inname = taskname + '.in'
465 try:
466 outname = outname.replace('%', taskname)
467 except NameError:
468 outname = taskname + '.out'
469 try:
470 ansname = ansname.replace('%', taskname)
471 except NameError:
472 ansname = taskname + '.ans'
473 else:
474 inname = inname.replace('%', taskname)
475 outname = outname.replace('%', taskname)
476 if tester:
477 ansname = ansname.replace('%', taskname)
478 if not stdio or tester or not options.erase:
479 if os.path.exists(inname): os.remove(inname)
480 if os.path.exists(outname): os.remove(outname)
481 if (tester or not options.erase) and ansname:
482 if os.path.exists(ansname): os.remove(ansname)
483 continue
484
485 try:
486 name
487 except NameError, error:
488 if str(error).count('name') == 1:
489 raise NameError, 'configuration ' + str(error), sys.exc_info()[2]
490 else:
491 raise NameError, 'configuration ' + str(error).replace('name ', 'variable ', 1), sys.exc_info()[2]
492
493 try:
494 if not stdio:
495 inname
496 outname
497 testcaseinname
498 if tester:
499 outname
500 if ansname:
501 testcaseoutname
502 else:
503 testcaseoutname
504 except NameError, error:
505 raise NameError, 'configuration ' + str(error).replace('name ', 'variable ', 1), sys.exc_info()[2]
506
507 if not options.erase:
508 try:
509 inname
510 except NameError:
511 inname = taskname + '.in'
512 try:
513 outname
514 except NameError:
515 outname = taskname + '.out'
516 try:
517 ansname
518 except NameError:
519 ansname = taskname + '.ans'
520
521 if options.pause:
522 try:
523 pause
524 except NameError, error:
525 if os.name == 'posix':
526 pause = 'read -s -n 1'
527 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 complete.'
528 elif os.name == 'nt':
529 pause = 'pause'
530 else:
531 raise NameError, 'configuration ' + str(error).replace('name ', 'variable ') + ' and cannot be devised automatically', sys.exc_info()[2]
532
533 if not dummyinname:
534 dummyinname = testcaseinname
535 if not dummyoutname and (not tester or ansname):
536 dummyoutname = testcaseoutname
537
538 dummyinname = dummyinname.replace('%', taskname)
539 dummyoutname = dummyoutname.replace('%', taskname)
540 testcaseinname = testcaseinname.replace('%', taskname)
541 if not stdio or not options.erase:
542 inname = inname.replace('%', taskname)
543 outname = outname.replace('%', taskname)
544 try:
545 ansname = ansname.replace('%', taskname)
546 except NameError:
547 pass
548 if tester:
549 try: inname = inname.replace('%', taskname)
550 except NameError: pass
551 outname = outname.replace('%', taskname)
552 if ansname:
553 ansname = ansname.replace('%', taskname)
554 testcaseoutname = testcaseoutname.replace('%', taskname)
555 else:
556 testcaseoutname = testcaseoutname.replace('%', taskname)
557
558 if isinstance(padwithzeroestolength, tuple):
559 padwithzeroestolength, paddummieswithzeroestolength = padwithzeroestolength
560 else:
561 paddummieswithzeroestolength = padwithzeroestolength
562
563 if options.python:
564 dummies = ()
565 s = ' '.join(args)
566 tests = eval(s)
567 try:
568 tests.__iter__
569 except AttributeError:
570 tests = (tests,)
571 elif len(args):
572 if os.path.exists(args[0]):
573 name = args[0]
574 del args[0]
575 if len(args) > 1:
576 dummies = ()
577 tests = args
578 elif len(args):
579 dummies = ()
580 s = args[0]
581 if len(s) < padwithzeroestolength:
582 s = s.zfill(padwithzeroestolength)
583 if existstestcase(testcaseinname.replace('$', s)):
584 tests = (s,)
585 else:
586 try:
587 tests = eval(args[0])
588 try:
589 tests.__iter__
590 except AttributeError:
591 tests = (tests,)
592 except Exception:
593 tests = (s,)
594
595 if options.exclude:
596 testsexcluded = []
597 for i in options.exclude:
598 v = eval(i)
599 try:
600 testsexcluded.extend(v)
601 except TypeError:
602 testsexcluded.append(v)
603
604 # Windows doesn't like paths beginning with .\ and not ending with an extension
605 name = os.path.normcase(name)
606 if name.startswith('.\\'):
607 name = name[2:]
608
609 newpointmap = {}
610
611 for i in pointmap:
612 try:
613 for j in i:
614 newpointmap[j] = pointmap[i]
615 except TypeError:
616 newpointmap[i] = pointmap[i]
617
618 pointmap = newpointmap
619
620 if maxtime > 0:
621 strmaxtime = '/%.3f' % maxtime
622 else:
623 strmaxtime = ''
624
625 padoutputtolength = 0
626 ntests = []
627
628 for j in dummies:
629 try:
630 j.__iter__
631 except AttributeError:
632 j = (j,)
633 ntests.append((j, True))
634 for i in j:
635 s = str(i)
636 if len(s) < paddummieswithzeroestolength:
637 s = s.zfill(paddummieswithzeroestolength)
638 s = 'sample ' + s
639 if padoutputtolength < len(s):
640 padoutputtolength = len(s)
641
642 for j in tests:
643 try:
644 j.__iter__
645 except AttributeError:
646 j = (j,)
647 ntests.append((j, False))
648 for i in j:
649 s = str(i)
650 if len(s) < padwithzeroestolength:
651 s = s.zfill(padwithzeroestolength)
652 if padoutputtolength < len(s):
653 padoutputtolength = len(s)
654
655 tests = ntests
656 score = maxpoints = ncorrect = ntotal = ncorrectvalued = nvalued = 0
657
658 if options.copyonly:
659 j, isdummy = tests[-1]
660 if isdummy:
661 realinname = dummyinname
662 realoutname = dummyoutname
663 else:
664 realinname = testcaseinname
665 realoutname = testcaseoutname
666 for i in j:
667 if i in testsexcluded and not isdummy:
668 continue
669 s = str(i)
670 if isdummy:
671 if len(s) < paddummieswithzeroestolength:
672 s = s.zfill(paddummieswithzeroestolength)
673 else:
674 if len(s) < padwithzeroestolength:
675 s = s.zfill(padwithzeroestolength)
676 copytestcase(realinname.replace('$', s), inname)
677 if ansname:
678 copytestcase(realoutname.replace('$', s), ansname)
679 continue
680
681 for j, isdummy in tests:
682 ncorrectgrp = 0
683 ntotalgrp = 0
684 scoregrp = 0
685 maxpointsgrp = 0
686 if isdummy:
687 realinname = dummyinname
688 realoutname = dummyoutname
689 else:
690 realinname = testcaseinname
691 realoutname = testcaseoutname
692 for i in j:
693 if i in testsexcluded and not isdummy:
694 continue
695 ntotalgrp += 1
696 s = str(i)
697 if isdummy:
698 npoints = 0
699 if len(s) < paddummieswithzeroestolength:
700 s = s.zfill(paddummieswithzeroestolength)
701 spref = 'sample '
702 else:
703 npoints = pointmap.get(None, 1)
704 npoints = pointmap.get(i, npoints)
705 maxpointsgrp += npoints
706 if npoints:
707 nvalued += 1
708 if len(s) < padwithzeroestolength:
709 s = s.zfill(padwithzeroestolength)
710 spref = ''
711 print ' ' * (padoutputtolength - len(spref + s)) + spref + s + ':',
712 sys.stdout.flush()
713 outputdata = open(os.devnull, 'w')
714 if stdio:
715 f = tempfile.NamedTemporaryFile(delete=False)
716 inputdatafname = f.name
717 f.close()
718 copytestcase(realinname.replace('$', s), inputdatafname)
719 inputdata = open(inputdatafname, 'rU')
720 if options.erase:
721 tempoutput = tempfile.TemporaryFile('w+')
722 else:
723 tempoutput = open(outname, 'w+')
724 try:
725 proc = subprocess.Popen(name, stdin=inputdata, stdout=tempoutput, stderr=outputdata, universal_newlines=True)
726 except OSError, error:
727 raise OSError, 'The program to be tested cannot be launched: ' + str(error), sys.exc_info()[2]
728 else:
729 if os.path.exists(outname):
730 os.remove(outname)
731 copytestcase(realinname.replace('$', s), inname)
732 try:
733 proc = subprocess.Popen(name, stdin=outputdata, stdout=outputdata, stderr=outputdata, universal_newlines=True)
734 except OSError, error:
735 raise OSError, 'The program to be tested cannot be launched: ' + str(error), sys.exc_info()[2]
736 cl = clock()
737 if maxtime > 0:
738 while 1:
739 proc.poll()
740 elapsed = clock() - cl
741 if proc.returncode == None:
742 if elapsed >= maxtime:
743 print '%.3f%s s, 0/%d, time limit exceeded' % (elapsed, strmaxtime, npoints)
744 sys.stdout.flush()
745 while proc.returncode == None:
746 try:
747 proc.terminate()
748 except OSError:
749 pass
750 except AttributeError:
751 try:
752 os.kill(proc.pid, signal.SIGTERM)
753 except Exception:
754 pass
755 proc.poll()
756 outputdata.close()
757 if stdio:
758 tempoutput.close()
759 break
760 else:
761 print '%.3f%s s,' % (elapsed, strmaxtime),
762 sys.stdout.flush()
763 elapsed = 0
764 if stdio:
765 tempoutput.seek(0)
766 lines = tempoutput.readlines()
767 tempoutput.close()
768 break
769 if elapsed >= maxtime:
770 continue
771 else:
772 data = proc.communicate()
773 elapsed = clock() - cl
774 print '%.3f%s s,' % (elapsed, strmaxtime),
775 sys.stdout.flush()
776 if stdio:
777 tempoutput.seek(0)
778 lines = tempoutput.readlines()
779 tempoutput.close()
780 outputdata.close()
781 if stdio:
782 inputdata.close()
783 try:
784 os.unlink(inputdatafname)
785 except Exception:
786 pass
787 if proc.returncode > 0:
788 print '0/%d, non-zero return code %d' % (npoints, proc.returncode)
789 sys.stdout.flush()
790 elif proc.returncode < 0:
791 print '0/%d, terminated by signal %d' % (npoints, -proc.returncode)
792 sys.stdout.flush()
793 else:
794 if not tester:
795 if stdio:
796 outputdata = opentestcase(realoutname.replace('$', s))
797 r = 0
798 data = outputdata.read().splitlines(True)
799 if len(lines) != len(data):
800 r = 1
801 else:
802 for i in zip(lines, data):
803 if i[0] != i[1]:
804 r = 1
805 break
806 outputdata.close()
807 else:
808 try:
809 inputdata = open(outname, 'rU')
810 except IOError:
811 print '0/%g, output file not created or not readable' % npoints
812 sys.stdout.flush()
813 r = None
814 else:
815 outputdata = opentestcase(realoutname.replace('$', s))
816 r = 0
817 lines = inputdata.readlines()
818 data = outputdata.read().splitlines(True)
819 if len(lines) != len(data):
820 r = 1
821 else:
822 for i in zip(lines, data):
823 if i[0] != i[1]:
824 r = 1
825 break
826 inputdata.close()
827 outputdata.close()
828 else:
829 if ansname:
830 copytestcase(realoutname.replace('$', s), ansname)
831 if stdio:
832 try: copytestcase(realinname.replace('$', s), inname)
833 except NameError: pass
834 outputdata = open(outname, 'w')
835 outputdata.writelines(lines)
836 outputdata.close()
837 try:
838 proc = subprocess.Popen(tester, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
839 except OSError, error:
840 raise OSError, 'The tester application cannot be launched: ' + str(error), sys.exc_info()[2]
841 data = proc.communicate()
842 r = proc.returncode
843 if tester and data[0]:
844 data = ''.join((' (', data[0].strip(), ')'))
845 else:
846 data = ''
847 if r:
848 print '0/%g, wrong answer%s' % (npoints, data)
849 sys.stdout.flush()
850 elif r == 0:
851 print '%g/%g, OK%s' % (npoints, npoints, data)
852 sys.stdout.flush()
853 scoregrp += npoints
854 ncorrectgrp += 1
855 if npoints:
856 ncorrectvalued += 1
857 if ntotalgrp:
858 if scoregrp < maxpointsgrp:
859 scoregrp = 0
860 if ntotalgrp > 1:
861 print 'Group total: %d/%d tests; %g/%g points' % (ncorrectgrp, ntotalgrp, scoregrp, maxpointsgrp)
862 sys.stdout.flush()
863 ncorrect += ncorrectgrp
864 ntotal += ntotalgrp
865 score += scoregrp
866 maxpoints += maxpointsgrp
867
868 if options.erase:
869 if not stdio or tester:
870 if os.path.exists(inname): os.remove(inname)
871 if os.path.exists(outname): os.remove(outname)
872 if tester and ansname:
873 if os.path.exists(ansname): os.remove(ansname)
874 elif stdio:
875 copytestcase(realinname.replace('$', s), inname)
876 copytestcase(realoutname.replace('$', s), ansname)
877 if nvalued != ntotal:
878 print 'Grand total: %d/%d tests (%d/%d valued); %g/%g points; weighted score: %g/%g' % (ncorrect, ntotal, ncorrectvalued, nvalued, score, maxpoints, (score*taskweight/maxpoints if not score*taskweight%maxpoints else float(score*taskweight)/maxpoints) if maxpoints else 0, taskweight)
879 else:
880 print 'Grand total: %d/%d tests; %g/%g points; weighted score: %g/%g' % (ncorrect, ntotal, score, maxpoints, (score*taskweight/maxpoints if not score*taskweight%maxpoints else float(score*taskweight)/maxpoints) if maxpoints else 0, taskweight)
881
882 scoresumoveralltasks += (score*taskweight/maxpoints if not score*taskweight%maxpoints else float(score*taskweight)/maxpoints) if maxpoints else 0
883 scoremaxoveralltasks += taskweight
884 ntasks += 1
885 nfulltasks += int((score == maxpoints) if maxpoints else (taskweight == 0))
886
887 os.chdir(oldcwd)
888
889 if options.clean or options.copyonly:
890 sys.exit()
891
892 if ntasks != 1:
893 print
894 print 'Grand grand total: %g/%g weighted points; %d/%d problems solved fully' % (scoresumoveralltasks, scoremaxoveralltasks, nfulltasks, ntasks)
895
896 if options.pause:
897 print 'Press any key to exit... ',
898 sys.stdout.flush()
899 os.system(pause + ' >' + os.devnull)