示例#1
0
    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)
示例#3
0
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)
示例#4
0
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()
示例#6
0
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)
示例#7
0
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}...')
示例#8
0
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)