comparison testcases.py @ 90:1fb319ec33af

Skimming mode added (-k/--skim option) In skimming mode, as soon as a single test case within a test group is failed, the remaining test cases in the same group are skipped. Bug fix and simply a bit of refactoring: TestCase.has_iofiles and TestCase.has_ansfile are now defined (the meaning should be clear from the names).
author Oleg Oshmyan <chortos@inbox.lv>
date Mon, 28 Feb 2011 15:32:22 +0000
parents 3ae6cb69e4ef
children c62c9bfd614a
comparison
equal deleted inserted replaced
89:3ae6cb69e4ef 90:1fb319ec33af
50 50
51 51
52 # Exceptions 52 # Exceptions
53 53
54 class TestCaseNotPassed(Exception): __slots__ = () 54 class TestCaseNotPassed(Exception): __slots__ = ()
55 class TestCaseSkipped(TestCaseNotPassed): __slots__ = ()
55 class TimeLimitExceeded(TestCaseNotPassed): __slots__ = () 56 class TimeLimitExceeded(TestCaseNotPassed): __slots__ = ()
56 class CPUTimeLimitExceeded(TimeLimitExceeded): __slots__ = () 57 class CPUTimeLimitExceeded(TimeLimitExceeded): __slots__ = ()
57 class WallTimeLimitExceeded(TimeLimitExceeded): __slots__ = () 58 class WallTimeLimitExceeded(TimeLimitExceeded): __slots__ = ()
58 class MemoryLimitExceeded(TestCaseNotPassed): __slots__ = () 59 class MemoryLimitExceeded(TestCaseNotPassed): __slots__ = ()
59 class CanceledByUser(TestCaseNotPassed): __slots__ = () 60 class CanceledByUser(TestCaseNotPassed): __slots__ = ()
158 else: 159 else:
159 case.realinname = case.problem.config.dummyinname 160 case.realinname = case.problem.config.dummyinname
160 case.realoutname = case.problem.config.dummyoutname 161 case.realoutname = case.problem.config.dummyoutname
161 162
162 @abstractmethod 163 @abstractmethod
163 def test(case): raise NotImplementedError 164 def test(case):
165 raise NotImplementedError
164 166
165 def __call__(case, callback): 167 def __call__(case, callback):
166 case.has_called_back = False 168 case.has_called_back = False
167 case.files_to_delete = [] 169 case.files_to_delete = []
168 case.time_limit_string = case.wall_time_limit_string 170 case.time_limit_string = case.wall_time_limit_string
175 elif getattr(case, 'time_stopped', None) is None: 177 elif getattr(case, 'time_stopped', None) is None:
176 case.time_stopped = now 178 case.time_stopped = now
177 if not case.has_called_back: 179 if not case.has_called_back:
178 callback() 180 callback()
179 case.cleanup() 181 case.cleanup()
182
183 @property
184 def has_iofiles(case):
185 return False
186
187 @property
188 def has_ansfile(case):
189 return False
180 190
181 def cleanup(case): 191 def cleanup(case):
182 #if getattr(case, 'infile', None): 192 #if getattr(case, 'infile', None):
183 # case.infile.close() 193 # case.infile.close()
184 #if getattr(case, 'outfile', None): 194 #if getattr(case, 'outfile', None):
227 except IOError: 237 except IOError:
228 e = sys.exc_info()[1] 238 e = sys.exc_info()[1]
229 raise CannotReadAnswerFile(e) 239 raise CannotReadAnswerFile(e)
230 240
231 241
242 class SkippedTestCase(TestCase):
243 __slots__ = ()
244
245 def test(case, callback):
246 raise TestCaseSkipped
247
248
232 class ValidatedTestCase(TestCase): 249 class ValidatedTestCase(TestCase):
233 __slots__ = 'validator' 250 __slots__ = 'validator'
234 251
235 def __init__(case, *args): 252 def __init__(case, *args):
236 TestCase.__init__(case, *args) 253 TestCase.__init__(case, *args)
276 293
277 294
278 class BatchTestCase(ValidatedTestCase): 295 class BatchTestCase(ValidatedTestCase):
279 __slots__ = () 296 __slots__ = ()
280 297
298 @property
299 def has_iofiles(case):
300 return (not case.problem.config.stdio or
301 case.validator and not callable(case.validator))
302
303 @property
304 def has_ansfile(case):
305 return case.validator and not callable(case.validator)
306
281 def test(case, callback): 307 def test(case, callback):
282 case.open_infile() 308 case.open_infile()
283 case.time_started = None
284 if case.problem.config.stdio: 309 if case.problem.config.stdio:
285 if options.erase and not case.validator or not case.problem.config.inname: 310 if options.erase and not case.validator or not case.problem.config.inname:
286 # TODO: re-use the same file name if possible 311 # TODO: re-use the same file name if possible
287 # FIXME: 2.5 lacks the delete parameter 312 # FIXME: 2.5 lacks the delete parameter
288 with tempfile.NamedTemporaryFile(delete=False) as f: 313 with tempfile.NamedTemporaryFile(delete=False) as f:
412 yield problem.test_context_end 437 yield problem.test_context_end
413 for k, group in enumerate(prob.config.tests): 438 for k, group in enumerate(prob.config.tests):
414 if not group: 439 if not group:
415 continue 440 continue
416 yield problem.TestGroup(prob.config.groupweight.get(k, prob.config.groupweight.get(None))) 441 yield problem.TestGroup(prob.config.groupweight.get(k, prob.config.groupweight.get(None)))
442 case_type = _types[prob.config.kind]
417 for j, i in enumerate(group): 443 for j, i in enumerate(group):
418 s = str(i).zfill(prob.config.padtests) 444 s = str(i).zfill(prob.config.padtests)
419 yield _types[prob.config.kind](prob, s, False, getpoints(i, j, k)) 445 if not (yield case_type(prob, s, False, getpoints(i, j, k))):
446 if options.skim:
447 case_type = SkippedTestCase
448 else:
449 yield
420 yield problem.test_context_end 450 yield problem.test_context_end
421 else: 451 else:
422 for i in prob.config.tests: 452 for i in prob.config.tests:
423 s = str(i).zfill(prob.config.padtests) 453 s = str(i).zfill(prob.config.padtests)
424 prob.cache.padoutput = max(prob.cache.padoutput, len(s)) 454 prob.cache.padoutput = max(prob.cache.padoutput, len(s))