import sys import traceback import time import io import tempfile import subprocess import os def run_code_against_tests(user_code, test_code): local_ns = {} output = '' start = time.perf_counter() error = None passed = False temp_file = None try: # Check if unittest is used in test_code if 'unittest' in test_code: # Write user code + test code to a temp file with tempfile.NamedTemporaryFile('w+', suffix='.py', delete=False, encoding='utf-8') as f: combined_code = f"{user_code}\n\n{test_code}" f.write(combined_code) f.flush() temp_file = f.name # Run the file as a subprocess try: proc = subprocess.run( [sys.executable, temp_file], capture_output=True, text=True, timeout=10, encoding='utf-8' ) output = proc.stdout if proc.stderr: output += f"\n{proc.stderr}" passed = proc.returncode == 0 if not passed: error = f"Tests failed. Return code: {proc.returncode}\n{output}" else: # For successful unittest runs, the stderr contains the test results if proc.stderr and "OK" in proc.stderr: output = proc.stderr # Use stderr as the main output for unittest except subprocess.TimeoutExpired: passed = False error = "Code execution timed out after 10 seconds" output = "Execution timed out" else: # Capture stdout old_stdout = sys.stdout captured_output = io.StringIO() sys.stdout = captured_output try: # Execute user code exec(user_code, {}, local_ns) # Execute test code (should raise AssertionError if fail) exec(test_code, local_ns, local_ns) passed = True except AssertionError as e: passed = False error = f"Assertion failed: {str(e)}" except Exception as e: passed = False error = f"Runtime error: {traceback.format_exc()}" finally: output = captured_output.getvalue() sys.stdout = old_stdout except Exception as e: passed = False error = f"Execution error: {traceback.format_exc()}" finally: # Clean up temporary file if temp_file and os.path.exists(temp_file): try: os.unlink(temp_file) except Exception as e: print(f"Warning: Could not delete temp file {temp_file}: {e}") runtime = time.perf_counter() - start result = { 'passed': passed, 'output': output.strip() if output else '', 'runtime': runtime, 'error': error if not passed else None } return result