Skip to content

Instantly share code, notes, and snippets.

@HexF
Created April 5, 2021 14:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HexF/480809533bc19573447727a23e1c9021 to your computer and use it in GitHub Desktop.
Save HexF/480809533bc19573447727a23e1c9021 to your computer and use it in GitHub Desktop.
EMKC Contest Test Bench Tool

EMKC Contest Test Bench Tool

I will probably make a repo for this one day, but for now this will do.

What this does:

  • Queries emkc.org for contest info
  • Queries piston with your code and args, exactly as it would be when being tested by EMKC.
  • Compares actual output against real, indicating failed and passed tests.

Complain about code quality in comments.

Usage

Ensure requests module is install, along with Python 3.4+.

python3 bench.py [contest_id] [source_file]

contest_id is from the url: https://emkc.org/contests/30/hello-world would be 30

Enquire source_file has the correct extension for the language, or is one of pistons many listed alises for the language.

Give it a few seconds to query the server, and it will go.

#!/usr/bin/env python3
import requests
import re
import json
import html
import sys
class EMKCWrapper:
BASE_URL="https://emkc.org"
@staticmethod
def get_contest_by_id(id):
contests_html = requests.get(f'{EMKCWrapper.BASE_URL}/contests').text
select_regex = re.compile(f'"/contests/{id}/(.*?)"')
slug = select_regex.search(contests_html).group(1)
contest_url = f'{EMKCWrapper.BASE_URL}/contests/{id}/{slug}'
contest_html = requests.get(contest_url).text
contest_regex = re.compile(r'data-contest="(.*?)"')
contest_data_raw = contest_regex.search(contest_html).group(1)
contest_data = html.unescape(contest_data_raw)
json_data = json.loads(contest_data)
return EMKCWrapper.Contest(json_data)
class Contest:
def __init__(self, data):
self.data = data
def get_test_cases(self):
data = self.data
inputs = data['input'].split('\n')
outputs = data['output'].split('\n')
cases = []
for i,output in enumerate(outputs):
inp = inputs[i]
cases.append(EMKCWrapper.Contest.TestCase(inp.split('|'), output))
return cases
def get_disallowed_languages(self):
return self.data['disallowed_languages'].split(',')
class TestCase:
def __init__(self, args, output):
self.args = args
self.output = output.strip()
def __repr__(self):
return f"TestCase(args={repr(self.args)}, output=\"{self.output}\")"
def evaluate(self, program, language):
result = PistonWrapper.execute(language,
program,
'\n'.join(self.args),
self.args)
passed = result['stdout'].strip() == self.output
return (passed, result)
class PistonWrapper:
BASE_URL="https://emkc.org/api/v1/piston"
@staticmethod
def get_languages():
api_response = requests.get(f"{PistonWrapper.BASE_URL}/versions").json()
return api_response
@staticmethod
def execute(language, source, stdin="", args=[]):
body = {
'language': language,
'source': source,
'stdin': stdin,
'args': args
}
request = requests.post(f"{PistonWrapper.BASE_URL}/execute", json=body)
return request.json()
def bench(contest_id, source, language_or_filename):
contest = EMKCWrapper.get_contest_by_id(contest_id)
test_cases = contest.get_test_cases()
print(f"Contest: {contest.data['name']} ({contest_id})")
print(f"Active? {contest.data['active']}")
print()
print(f"Code Length: {len(source)}")
language = None
alias = language_or_filename.split(".")[-1].lower()
for lang in PistonWrapper.get_languages():
name = lang['name']
aliases = lang['aliases']
if name == alias or alias in aliases:
language = name
if language is None:
print(f"Code Language: Unknown ({alias})")
exit(1)
print(f"Code Language: {language} ({alias})")
print()
program = source
if type(program) == bytes:
program = source.decode()
for test_case in test_cases:
sys.stdout.write(f"[WAIT] {test_case}")
passed, trace = test_case.evaluate(program, language)
if passed:
print(f"\r[GOOD] {test_case}")
else:
print(f"\r[FAIL] {test_case}")
print("Got:")
print('\t' + trace['stdout'].replace('\n', '\t'))
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('contest_id')
parser.add_argument('source_file')
args = parser.parse_args()
with open(args.source_file, "rb") as f:
bench(args.contest_id, f.read(), args.source_file)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment