I am creating a website with coding questions. When a user submits a code for a question I use the contents of the question to create a python file and then I send it to the piston API for evaluation.
I use this function to create the python files content as string
fn inject_code(question_id: i32, content: String, db_pool: DbPool) -> String {
let question= get_single_question(question_id, db_pool).expect("Expected to find question");
let imports= std::fs::read_to_string("injections/function_top.py").unwrap();
let change_name = format!("__some_function = Solution.{}", question.function_name);
let cases = question.cases;
let py_runner = std::fs::read_to_string("injections/function.py").unwrap();
format!("{imports}\n\n{content}\n\n{change_name}\n\n{cases}\n\n{py_runner}")
}
Where injection/function_top looks like:
from typing import *
from dataclasses import dataclass
@dataclass
class TestCase:
inputs: tuple
expected: Any
and injection/function looks like:
import io
from contextlib import redirect_stdout
import json
test_results = []
for case_id, test_case in enumerate(cases):
args = test_case.inputs
result = test_case.expected
with io.StringIO() as buf, redirect_stdout(buf):
error = None
correct = False
try:
correct = __some_function(*args) == result
except Exception as e:
error = e
function_stdout = buf.getvalue()
case_signature = f"{str(args)} -> {str(result)}"
test_results.append(
{"is_correct": correct, "case_stdout": function_stdout, "error": error, "case_signature": case_signature}
)
print(json.dumps(test_results, default=str)) # Ensures exceptions are stringified
The cases are stored as native python files such as this:
cases = [
TestCase(inputs=([], []), expected=[]),
TestCase(inputs=([1], [2]), expected=[1, 2]),
TestCase(inputs=([2], [1]), expected=[2, 1]),
TestCase(inputs=([3, 2, 1], []), expected=[3, 2, 1]),
TestCase(inputs=([], [1, 2, 3]), expected=[1, 2, 3]),
TestCase(inputs=([2, 3], [6, 4, 2]), expected=[2, 3, 6, 4, 2]),
]
and if we run this line of code for debug:
let injected_code = inject_code(id, content, pool);
std::fs::write("test.py", &injected_code).unwrap(); // debug the created python file
we get test.py (this is the file that would be sent to the piston API)
from typing import *
from dataclasses import dataclass
@dataclass
class TestCase:
inputs: tuple
expected: Any
class Solution:
def concat(arr_1: List[int], arr_2: List[int]):
return arr_1 + arr_2
__some_function = Solution.concat
cases = [
TestCase(inputs=([], []), expected=[]),
TestCase(inputs=([1], [2]), expected=[1, 2]),
TestCase(inputs=([2], [1]), expected=[2, 1]),
TestCase(inputs=([3, 2, 1], []), expected=[3, 2, 1]),
TestCase(inputs=([], [1, 2, 3]), expected=[1, 2, 3]),
TestCase(inputs=([2, 3], [6, 4, 2]), expected=[2, 3, 6, 4, 2]),
]
import io
from contextlib import redirect_stdout
import json
test_results = []
for case_id, test_case in enumerate(cases):
args = test_case.inputs
result = test_case.expected
with io.StringIO() as buf, redirect_stdout(buf):
error = None
correct = False
try:
correct = __some_function(*args) == result
except Exception as e:
error = e
function_stdout = buf.getvalue()
case_signature = f"{str(args)} -> {str(result)}"
test_results.append(
{"is_correct": correct, "case_stdout": function_stdout, "error": error, "case_signature": case_signature}
)
print(json.dumps(test_results, default=str)) # Ensures exceptions are stringified
Some explanation: I am printing the final result because piston API only returns the program output. It is printed as JSON so that I can easily send it to my frontend. I am redirecting the stdout while the function is tested so that the user can see what was printed when the test case ran. I started by using a dictionary for my test cases but since the keys need to be hashable that turned out to be a problem.
I wanted the test cases to be written in native python so that any valid python object could be the answer or argument to the test case.
Is there any way I can improve this system? One mini problem that I have right now is that when creating a case my editor complains that "TestCase" is not defined.