# flake8: noqa """This template is used inside snekbox to evaluate and test user code.""" import ast import base64 import io import os import sys import traceback import unittest from itertools import chain from types import ModuleType, SimpleNamespace from typing import NoReturn from unittest import mock ### USER CODE class RunnerTestCase(unittest.TestCase): ### UNIT CODE normal_exit = False def _exit_sandbox(code: int) -> NoReturn: """ Exit the sandbox by printing the result to the actual stdout and exit with the provided code. Codes: - 0: Executed with success - 5: Syntax error while parsing user code - 6: Uncaught exception while loading user code - 99: Internal error 137 can also be generated by NsJail when killing the process. """ print(RESULT.getvalue(), file=ORIGINAL_STDOUT, end="") global normal_exit normal_exit = True sys.exit(code) def _load_user_module() -> ModuleType: """Load the user code into a new module and return it.""" code = base64.b64decode(USER_CODE).decode("utf8") try: ast.parse(code, "") except SyntaxError: RESULT.write("".join(traceback.format_exception(*sys.exc_info(), limit=0))) _exit_sandbox(5) _module = ModuleType("module") exec(code, _module.__dict__) return _module def _main() -> None: suite = unittest.defaultTestLoader.loadTestsFromTestCase(RunnerTestCase) result = suite.run(unittest.TestResult()) RESULT.write(str(int(result.wasSuccessful()))) if not result.wasSuccessful(): RESULT.write( ";".join(chain( (error[0]._testMethodName.removeprefix("test_") for error in result.errors), (failure[0]._testMethodName.removeprefix("test_") for failure in result.failures) )) ) _exit_sandbox(0) try: # Fake file object not writing anything DEVNULL = SimpleNamespace(write=lambda *_: None, flush=lambda *_: None) RESULT = io.StringIO() ORIGINAL_STDOUT = sys.__stdout__ # stdout/err is patched in order to control what is outputted by the runner sys.__stdout__ = sys.stdout = DEVNULL sys.__stderr__ = sys.stderr = DEVNULL # Load the user code as a global module variable try: module = _load_user_module() except BaseException as e: RESULT.write(f"Uncaught exception while loading user code: {e}") _exit_sandbox(6) _main() except BaseException as e: if isinstance(e, SystemExit) and normal_exit: raise e from None RESULT.write(f"Uncaught exception inside runner: {e}") _exit_sandbox(99)