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