File size: 3,184 Bytes
54a19c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import subprocess
import time
import os
import tempfile
import ast
from .models import ExecutionResult

def run_code_with_tests(code: str, test_code: str, timeout: float = 5.0) -> ExecutionResult:
    # Syntax check
    try:
        ast.parse(code)
    except SyntaxError as e:
        return ExecutionResult(
            compile_success=False,
            runtime_errors=str(e),
            test_passed=0,
            test_total=0,
            execution_time_seconds=0.0,
            success=False
        )
    
    # Combine code and test definitions
    full_code = f"""
import sys
import unittest
import time
import io

{code}

{test_code}

if __name__ == '__main__':
    stream = io.StringIO()
    runner = unittest.TextTestRunner(stream=stream, verbosity=2)
    start_time = time.time()
    result = runner.run(unittest.defaultTestLoader.loadTestsFromModule(sys.modules[__name__]))
    end_time = time.time()
    
    output = stream.getvalue()
    
    print(f"|CODEARENA_STATS|{{result.wasSuccessful()}}|{{result.testsRun - len(result.failures) - len(result.errors)}}|{{result.testsRun}}|{{end_time - start_time}}|")
    if not result.wasSuccessful():
        print(output)
"""
    
    with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
        f.write(full_code)
        temp_file = f.name
    
    start_wall = time.time()
    try:
        process = subprocess.run(
            ['python', temp_file],
            capture_output=True,
            text=True,
            timeout=timeout
        )
        wall_time = time.time() - start_wall
        
        stdout = process.stdout
        stderr = process.stderr
        
        stats_line = None
        for line in stdout.split('\n'):
            if line.startswith('|CODEARENA_STATS|'):
                stats_line = line
                break
                
        if stats_line:
            parts = stats_line.split('|')
            success_str = parts[2]
            passed = int(parts[3])
            total = int(parts[4])
            exec_time = float(parts[5])
            
            return ExecutionResult(
                compile_success=True,
                runtime_errors=stderr if stderr else "",
                test_passed=passed,
                test_total=total,
                execution_time_seconds=exec_time,
                success=(success_str == 'True')
            )
        else:
            return ExecutionResult(
                compile_success=True,
                runtime_errors="Tests did not complete successfully or output was malformed. Stderr: " + stderr + "\nStdout: " + stdout,
                test_passed=0,
                test_total=1, # Assume at least 1 failed
                execution_time_seconds=wall_time,
                success=False
            )
            
    except subprocess.TimeoutExpired as e:
        return ExecutionResult(
            compile_success=True,
            runtime_errors="Execution timed out.",
            test_passed=0,
            test_total=1,
            execution_time_seconds=timeout,
            success=False
        )
    finally:
        if os.path.exists(temp_file):
            os.remove(temp_file)