def run(self, input, command=None, *args): """ Runs the program :param input: stdin :param command: The command to run (optional and generally only for internals) :param args: Any extra process arguments to specify :return: Returns a tuple (CompletedProcess, execution_time, TLE) """ start_time = time.time() try: res = sub.run(self._sub_placeholder_list( command or self.executor_info['command']) + list(args), text=True, input=input, stdout=sub.PIPE, stderr=sub.PIPE, timeout=float(get_option('timeout'))) return res, time.time() - start_time, False except sub.TimeoutExpired as e: # Sometimes returned as str, sometimes as bytes stdout = str(e.stdout, 'utf8') if type(e.stdout) == bytes else ( e.stdout or '') # If stream output is None stderr = str(e.stderr, 'utf8') if type(e.stderr) == bytes else ( e.stderr or '') # " return sub.CompletedProcess([], -1, stdout, stderr), time.time() - start_time, True
def do_POST(self): content_length = int( self.headers['Content-Length']) # <--- Gets the size of data problem = json.loads( self.rfile.read(content_length)) # <--- Gets the data itself name = fix_name(problem['name'].strip()) logging.info( f'Received problem "{name}" from {problem["group"]}. Contains {len(problem["tests"])} sample cases' ) self._set_response() self.wfile.write("POST request for {}".format( self.path).encode('utf-8')) # Make name unique src_lang = os.path.splitext(get_option('template_path'))[1] fname = name ctr = 1 while not fname or os.path.exists(fname + '.yml') or os.path.exists(fname + src_lang): fname = name + str(ctr) ctr += 1 # Write case file and source file write_cases_file(os.path.join(save_path, fname + '.yml'), problem) if not args.skip_source_file: try_write_source_file(os.path.join(save_path, fname), src_lang)
def try_write_source_file(fname, src_lang): is_linux = sys.platform == 'linux' or sys.platform == 'linux2' if not os.path.exists(get_option('template_path')): logging.warning( 'Template file does not exist. Skipping generation of source file' ) else: with open(fname + src_lang, 'w') as f: # Some sort of indicator to denote the associated data file f.write(f'{COMMENT_MAP[src_lang]} {fname}.yml\n') with open(get_option('template_path')) as ff: f.write(ff.read().replace('\r', '')) if is_linux: os.chmod(fname + src_lang, 0o777)
def write_cases_file(path, problem, checker=get_option("default_checker")): is_linux = sys.platform == 'linux' or sys.platform == 'linux2' with open( path, 'w' ) as f: # Writing cases manually for a bit more flexibility when formatting YAML # Shebang if is_linux: f.write('#!cptools-run\n') logging.debug( 'Linux machine detected: adding shebang to cases file...') f.write(f'checker: {checker}\n') f.write('cases:\n') # Number of cases is 0 if len(problem['tests']) == 0: problem['tests'].append({ 'input': 'foo', 'output': 'bar' }) # Any sample sequence for case in problem['tests']: inp = case['input'] + ('\n' if case['input'][-1] != '\n' else '') out = case['output'] + ('\n' if case['output'][-1] != '\n' else '') f.write(' - in: |\n') f.write(textwrap.indent(inp, ' ' * 6)) f.write(' out: |\n') f.write(textwrap.indent(out, ' ' * 6)) if is_linux: os.chmod(path, 0o777) # Help logging.debug( 'Linux machine detected: adding executable permission to cases file...' )
def main(): global save_path, args init_common(parser) args = parser.parse_args() init_common_options(args, False) logging.info('Started Competitive Companion Listener') save_path = get_option('saved_files_dir') logging.info(f'Files will be saved in {save_path}') port = args.port or DEFAULT_PORT logging.info(f'Starting HTTP server on port {port}...') server = HTTPServer(('localhost', port), RequestHandler) server.serve_forever()
def main(): common.init_common(parser) args = parser.parse_args() common.init_common_options(args, False) if args.stress_test: args.file_name += '.yml' logging.info(f'Making info file {args.file_name}...') with open(args.file_name, 'w') as f: f.write(data.get_default_stress_test_file()) else: tests_obj = {'tests': [{'input': 'foo', 'output': 'bar'} for _ in range(args.case_count)]} write_cases_file(args.file_name + '.yml', tests_obj, args.checker) logging.info(f'Generating cases file {args.file_name}.yml with {args.case_count} sample cases and checker "{args.checker}"') if args.make_source: fname = args.file_name ext = path.splitext(get_option('template_path'))[1] logging.info(f'Generating source file {fname}{ext}') try_write_source_file(fname, ext)
from cptools.gen import write_cases_file, try_write_source_file parser = argparse.ArgumentParser(description='Autogenerate test case (YML), source files, and stress-testing config' 'files') parser.add_argument('file_name', type=str, help='File name (without extension) of the YML file to generate.') parser.add_argument('-ms', '--make-source', help='Also generate a source file from the template file path specified in ' 'the config. Note that the extension of the source file will be the' 'same as that of the template', action='store_true') parser.add_argument('-cc', '--case_count', help='Adds the specified amount of test cases to the YML file, with ' 'placeholders being used as the input and output (foo and bar ' 'respectively)', type=int, default=1) parser.add_argument('-c', '--checker', help='The checker for the cases file. If not specified, it defaults to the' 'default_checker option in the config.yml file', type=str, default=get_option('default_checker')) parser.add_argument('-S', '--stress-test', help='Instead of generating test case and source files, it creates a stress' '-testing config file instead. Specify the name of the file (without ' 'xtension) in the file_name argument', action='store_true') def main(): common.init_common(parser) args = parser.parse_args() common.init_common_options(args, False) if args.stress_test: args.file_name += '.yml' logging.info(f'Making info file {args.file_name}...')
def main(): common.init_common(parser) args = parser.parse_args() common.init_common_options(args, True) cfg = data.get_config() logging.info(f'Running {args.src_file} using cases from {args.data_file}') logging.debug(f'Working directory: {os.getcwd()}') logging.debug(f'Timeout: {cfg["timeout"]}') logging.debug(f'Display Character Limit: {cfg["char_limit"]}') exc = compile_source_file(args.src_file, args.executor) # Load data logging.info('Loading test data...') if not os.path.exists(args.data_file): logging.error('Data file does not exist!') common.exit() try: with open(args.data_file) as f: tests = yaml.unsafe_load(f.read()) msg = data.validate_data_object(tests) if msg: logging.error(f'Error while parsing data: {msg}') common.exit() cases = tests['cases'] for i in range(len(cases)): if cases[i]['in'][-1] != '\n': cases[i]['in'] += '\n' if cases[i]['out'][-1] != '\n': cases[i]['out'] += '\n' except KeyError or IndexError: logging.error(f'Malformed test data. {Fore.RED}', exc_info=True) common.exit() # Checker checker = parse_checker(tests['checker']) checker.setup() # Run program if args.only_case is not None: if args.only_case >= len(cases): logging.error('Case index out of range!') common.exit() cases = [cases[args.only_case]] logging.warning(f'Only running case #{args.only_case}') char_limit = data.get_option('char_limit') timeout = data.get_option('timeout') print() # For formatting verdicts = [] for ind, case in enumerate(cases): case_in = case['in'] case_out = case['out'] try: res, elapsed, tle = exc.run(case_in) except UnicodeEncodeError: logging.error('Invalid character in Input', exc_info=True) common.exit() except UnicodeDecodeError: logging.error('Invalid character in Output/Error Stream', exc_info=True) common.exit() def print_verdict(verdict, verdict_clr, is_timeout=False, extra=''): elapsed_str = f'[>{timeout:.3f}s]' if is_timeout else f'[{elapsed:.3f}s]' print( f'{Style.BRIGHT}Case #{ind}: {verdict_clr}{verdict}{Style.RESET_ALL + Style.BRIGHT} {extra}{elapsed_str}{Style.RESET_ALL}' ) if tle: print_verdict('TLE', Style.DIM + Fore.WHITE, True) ac = False verdicts.append(Style.DIM + Fore.WHITE + 't') elif res.stderr or res.returncode: print_verdict('RTE', Fore.YELLOW, False, f'(Exit Code: {res.returncode}) ') ac = False verdicts.append(Fore.YELLOW + '!') else: if not case_out and not tests['checker'].startswith('custom'): ac, feedback = True, '' else: ac, feedback = checker.check(case_in, case_out, res.stdout) if ac: print_verdict('AC', Fore.LIGHTGREEN_EX) verdicts.append(Fore.LIGHTGREEN_EX + '*') else: feedback_str = f'({feedback}) ' if feedback else '' print_verdict('WA', Fore.LIGHTRED_EX, False, feedback_str) verdicts.append(Fore.LIGHTRED_EX + 'x') if not ac or args.list_all: def print_stream(label, text, style_before='', style_after=Style.RESET_ALL): print( f'== {label} ==\n{style_before}{common.truncate(text, char_limit)}{style_after}' ) if res.stderr: print_stream('Errors', res.stderr, Fore.LIGHTRED_EX) print_stream('Input', case_in) print_stream('Output', res.stdout) if case_out: print_stream('Expected Output', case_out) verdicts = [v + Style.RESET_ALL + Style.BRIGHT for v in verdicts] print(f'\n{Style.BRIGHT}Results: [ {" ".join(verdicts)} ]') # Cleanup exc.cleanup() checker.cleanup() common.exit(0)