blob: 7e21b97c3c669ed8f73bce734eddf846b38ffa6f (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
import ast
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
# Fake file object not writing anything
DEVNULL = SimpleNamespace(write=lambda *_: None, flush=lambda *_: None)
RESULT = io.StringIO()
ORIGINAL_STDOUT = sys.stdout
sys.stdout = DEVNULL
sys.stderr = DEVNULL
def _exit_sandbox(code: int) -> NoReturn:
"""
Codes:
- 0: Executed with success
- 5: Syntax error while parsing user code
- 99: Internal error
"""
result_content = RESULT.getvalue()
print(
f"{result_content}",
file=ORIGINAL_STDOUT
)
sys.exit(code)
def _load_user_module() -> ModuleType:
try:
ast.parse(USER_CODE, "<input>")
except SyntaxError:
RESULT.write("".join(traceback.format_exception(*sys.exc_info(), limit=0)))
_exit_sandbox(5)
_module = ModuleType("module")
exec(USER_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.lstrip("test_") for error in result.errors),
(failure[0]._testMethodName.lstrip("test_") for failure in result.failures)
))
)
_exit_sandbox(0)
try:
module = _load_user_module()
_main()
except Exception:
print("Uncaught exception:\n", file=RESULT)
traceback.print_exc(file=RESULT)
_exit_sandbox(99)
|