Mercurial > ~astiob > upreckon > hgweb
annotate test-svn.py @ 41:164395af969d
Cosmetical edit
subprocess.Popen always accepts TemporaryFile instances due to their implementation.
author | Oleg Oshmyan <chortos@inbox.lv> |
---|---|
date | Sun, 05 Dec 2010 15:00:27 +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) |