# HG changeset patch # User Oleg Oshmyan # Date 1298907142 0 # Node ID 1fb319ec33af111fc79713559efc9fdca173d4b3 # Parent 3ae6cb69e4ef7550c3076d123db56574dc712fa1 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). diff -r 3ae6cb69e4ef -r 1fb319ec33af problem.py --- a/problem.py Mon Feb 28 15:10:40 2011 +0000 +++ b/problem.py Mon Feb 28 15:32:22 2011 +0000 @@ -46,7 +46,7 @@ self.__dict__ = mydict class TestContext(object): - pass + __slots__ = () test_context_end = object() @@ -138,6 +138,8 @@ sys.stdout.flush() try: granted = case(lambda: (say('%7.3f%s s, ' % (case.time_stopped - case.time_started, case.time_limit_string), end=''), sys.stdout.flush())) + except testcases.TestCaseSkipped: + verdict = 'skipped due to skimming mode' except testcases.CanceledByUser: verdict = 'canceled by the user' except testcases.WallTimeLimitExceeded: @@ -187,6 +189,7 @@ comment = ' (%s)' % comment if granted >= 1: contexts[-1].case_correct() + prob.testcases.send(True) verdict = 'OK' + comment elif not granted: verdict = 'wrong answer' + comment @@ -206,8 +209,7 @@ sys.stdout.flush() return weighted, prob.config.taskweight finally: - if options.erase and (not prob.config.stdio or case and - (case.validator and not callable(case.validator))): + if options.erase and case and case.has_iofiles: for var in 'in', 'out': name = getattr(prob.config, var + 'name') if name: @@ -215,7 +217,7 @@ os.remove(name) except Exception: pass - if case.validator and not callable(case.validator): + if case.has_ansfile: if prob.config.ansname: try: os.remove(prob.config.ansname) diff -r 3ae6cb69e4ef -r 1fb319ec33af testcases.py --- a/testcases.py Mon Feb 28 15:10:40 2011 +0000 +++ b/testcases.py Mon Feb 28 15:32:22 2011 +0000 @@ -52,6 +52,7 @@ # Exceptions class TestCaseNotPassed(Exception): __slots__ = () +class TestCaseSkipped(TestCaseNotPassed): __slots__ = () class TimeLimitExceeded(TestCaseNotPassed): __slots__ = () class CPUTimeLimitExceeded(TimeLimitExceeded): __slots__ = () class WallTimeLimitExceeded(TimeLimitExceeded): __slots__ = () @@ -160,7 +161,8 @@ case.realoutname = case.problem.config.dummyoutname @abstractmethod - def test(case): raise NotImplementedError + def test(case): + raise NotImplementedError def __call__(case, callback): case.has_called_back = False @@ -178,6 +180,14 @@ callback() case.cleanup() + @property + def has_iofiles(case): + return False + + @property + def has_ansfile(case): + return False + def cleanup(case): #if getattr(case, 'infile', None): # case.infile.close() @@ -229,6 +239,13 @@ raise CannotReadAnswerFile(e) +class SkippedTestCase(TestCase): + __slots__ = () + + def test(case, callback): + raise TestCaseSkipped + + class ValidatedTestCase(TestCase): __slots__ = 'validator' @@ -278,9 +295,17 @@ class BatchTestCase(ValidatedTestCase): __slots__ = () + @property + def has_iofiles(case): + return (not case.problem.config.stdio or + case.validator and not callable(case.validator)) + + @property + def has_ansfile(case): + return case.validator and not callable(case.validator) + def test(case, callback): case.open_infile() - case.time_started = None if case.problem.config.stdio: if options.erase and not case.validator or not case.problem.config.inname: # TODO: re-use the same file name if possible @@ -414,9 +439,14 @@ if not group: continue yield problem.TestGroup(prob.config.groupweight.get(k, prob.config.groupweight.get(None))) + case_type = _types[prob.config.kind] for j, i in enumerate(group): s = str(i).zfill(prob.config.padtests) - yield _types[prob.config.kind](prob, s, False, getpoints(i, j, k)) + if not (yield case_type(prob, s, False, getpoints(i, j, k))): + if options.skim: + case_type = SkippedTestCase + else: + yield yield problem.test_context_end else: for i in prob.config.tests: diff -r 3ae6cb69e4ef -r 1fb319ec33af upreckon-vcs --- a/upreckon-vcs Mon Feb 28 15:10:40 2011 +0000 +++ b/upreckon-vcs Mon Feb 28 15:32:22 2011 +0000 @@ -19,6 +19,7 @@ parser.add_option('-x', '--auto-exit', dest='pause', action='store_false', default=True, help='do not wait for a key to be pressed after finishing testing') 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') parser.add_option('-t', '--detect-time', dest='autotime', action='store_true', default=False, help='spend a second detecting the most precise time measurement function') +parser.add_option('-k', '--skim', action='store_true', default=False, help='skip test groups as soon as one test case is failed') parser.add_option('--no-time-limits', dest='no_maxtime', action='store_true', default=False, help='disable all time limits') options, args = parser.parse_args()