Mercurial > ~astiob > upreckon > hgweb
annotate 1.20/test.py @ 21:ec6f1a132109
A pretty usable version
Test groups and testconfs in non-ZIP archives or ZIP archives with comments are not yet supported.
author | Oleg Oshmyan <chortos@inbox.lv> |
---|---|
date | Fri, 06 Aug 2010 15:39:29 +0000 |
parents | 5bfa23cd638d |
children |
rev | line source |
---|---|
7 | 1 #! /usr/bin/python |
8 | 2 # Copyright (c) 2009, 2010 Chortos-2 <chortos@inbox.lv> |
7 | 3 |
4 import os, sys, shutil, time, subprocess, filecmp, optparse, signal, tempfile, tarfile, zipfile | |
5 | |
20 | 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 | 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: | |
19
d4fc9341664e
Fixed an exception when tests.zip contained test cases in its root
Oleg Oshmyan <chortos@inbox.lv>
parents:
8
diff
changeset
|
287 m = f.getinfo(name) |
7 | 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) | |
20 | 300 m.filename = os.path.relpath(target) |
7 | 301 f.extract(m) |
302 f.close() | |
303 os.chdir(oldcwd) | |
304 return True | |
305 except KeyError: | |
306 f.close() | |
20 | 307 os.chdir(oldcwd) |
7 | 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 | |
8 | 882 scoresumoveralltasks += (score*taskweight/maxpoints if not score*taskweight%maxpoints else float(score*taskweight)/maxpoints) if maxpoints else 0 |
7 | 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() | |
19
d4fc9341664e
Fixed an exception when tests.zip contained test cases in its root
Oleg Oshmyan <chortos@inbox.lv>
parents:
8
diff
changeset
|
899 os.system(pause + ' >' + os.devnull) |