import os
import subprocess
import sys
import glob
from pathlib import Path
TEST_CASES = {
'simple_const.lamina': ['42'],
'arithmetic.lamina': ['5'],
'loops.lamina': ['15'],
'conditionals.lamina': ['100'],
'functions.lamina': ['80'],
'constants.lamina': ['42'],
'variables.lamina': ['10', '20', '30', '25', '50'],
'complex_arithmetic.lamina': ['277600'],
'nested_calls.lamina': ['256'],
'large_constants.lamina': ['42'],
'stress_test.lamina': ['210'],
'memory_test.lamina': ['100', '200', '300', '400', '500'],
'register_pressure.lamina': ['136'],
'stack_operations.lamina': ['650', '1150', '1650'],
'function_call_isolation.lamina': ['15', '16', '30', '24', '220'],
'edge_cases.lamina': ['0', '0', '-5', '100', '0', '42'],
'recursive_factorial.lamina': ['1', '1', '2', '6', '24'], 'recursive_fibonacci.lamina': ['0', '1', '1', '2', '3', '5'], 'recursive_sum.lamina': ['0', '1', '3', '6', '10', '15'], 'recursion_with_calculation.lamina': ['6'], 'stack_overflow_test.lamina': ['42'],
'heap_memory.lamina': ['50', '600'], 'stack_allocation.lamina': ['50', '90', '100'], 'load_store_operations.lamina': ['1'],
'pointer_operations.lamina': ['42', '100'], 'gep_variable_indices.lamina': ['30', '42', '30', '3230'], 'pointer_arithmetic_brainfuck.lamina': ['42'], 'struct_operations.lamina': ['500'], 'tuple_operations.lamina': ['0'], 'type_conversion.lamina': ['100', '60', '1', '1', '1', '1', '50'], 'external_functions.lamina': ['60', '100', '17', '123', '10'], 'debug_printing.lamina': ['27'],
'hello_world.lamina': ['Hello World'],
'io_basic.lamina': ['Hello'], 'io_pointer.lamina': ['42'], 'io_comprehensive.lamina': ['Hi!', '12345', 'DONE', '12445'], 'io_writeptr.lamina': ['OK'],
'primitive_types_simple.lamina': ['60', '60', '16', '16', '32', '32', '2000000', '64', '1', '67', '32', '64'], 'pointer_operations_simple.lamina': ['42', '100', '1000'], 'struct_operations_simple.lamina': ['30'], 'tuple_operations_simple.lamina': ['0'], 'type_conversions_simple.lamina': ['100'], 'primitive_types_fixed.lamina': ['60', '60', '16', '16', '32', '32', '2000000', '64', '1', '67'], 'pointer_operations_fixed.lamina': ['42', '100', '1000', '42'], 'tuple_operations_fixed.lamina': ['0'], 'type_conversions_fixed.lamina': ['100', '1000'], 'brainfuck_like.lamina': ['2'], 'gep_element_size_bug_test.lamina': ['3000002000001000'], 'struct_field_offset_bug_test.lamina': ['44444003333222011', '3000201'], 'division_small_types_bug_test.lamina': ['6', '14', '6', '16', '3'], 'floating_point_bug_test.lamina': ['32', '64', '123', '42'], 'heap_allocation_bug_test.lamina': ['12345', '600', '333', '123457831'], 'edge_cases_bug_test.lamina': ['127128128127', '-4093720114651070465', '20', '0', '1000'], 'dealloc_stack_vs_heap_bug_test.lamina': ['100042'], 'getfieldptr_offset_bug_test.lamina': ['3566'], 'gep_element_size_comprehensive_bug_test.lamina': ['42'], 'register_size_mismatch_bug_test.lamina': ['1738067755672081826'], 'stack_frame_overflow_bug_test.lamina': ['333222111'], 'floating_point_register_bug_test.lamina': ['3'], 'load_store_optimization_bug_test.lamina': ['305422896125369200'], 'calling_convention_bug_test.lamina': ['15'],
'stdin.lamina': ['65', '10', '66'], 'io_basic.lamina': ['Hello'], 'io_buffer.lamina': ['66', '117', '102'], 'io_types.lamina': ['@ATEST'], 'io_comprehensive.lamina': ['Hi!', '12345', 'DONE', '12445'], }
class Colors:
GREEN = '\033[92m'
RED = '\033[91m'
YELLOW = '\033[93m'
BLUE = '\033[94m'
BOLD = '\033[1m'
END = '\033[0m'
def print_colored(message, color):
print(f"{color}{message}{Colors.END}")
def run_command(cmd, cwd=None):
try:
result = subprocess.run(
cmd,
shell=True,
capture_output=True,
text=True,
cwd=cwd,
timeout=60,
errors='replace' )
return result.returncode == 0, result.stdout.strip(), result.stderr.strip()
except subprocess.TimeoutExpired:
return False, "", "Command timed out"
except Exception as e:
return False, "", str(e)
def compile_and_run_test(test_file):
project_root = Path(__file__).parent
testcase_path = project_root / 'testcases' / test_file
executable_name = test_file.replace('.lamina', '')
stdin_inputs = {
'stdin.lamina': 'A\nBUFFER_TEST\nB', 'io_buffer.lamina': 'Buf', }
compile_cmd = f"cargo run --release --quiet testcases/{test_file} "
success, stdout, stderr = run_command(compile_cmd, cwd=project_root)
if not success:
return False, f"Compilation failed: {stderr}"
stdin_input = stdin_inputs.get(test_file)
if stdin_input:
try:
result = subprocess.run(
['./stdin'], capture_output=True,
text=True,
cwd=project_root,
input=stdin_input,
timeout=60,
errors='replace' )
success = True stdout = result.stdout.strip()
stderr = result.stderr.strip()
except subprocess.TimeoutExpired:
return False, "Command timed out"
except Exception as e:
return False, f"Execution failed: {str(e)}"
else:
run_cmd = f"./{executable_name}"
success, stdout, stderr = run_command(run_cmd, cwd=project_root)
if not success:
return False, f"Execution failed: {stderr}"
output_lines = [line.strip() for line in stdout.split('\n') if line.strip()]
if test_file == 'stdin.lamina' and 'Results:' in output_lines:
results_start = output_lines.index('Results:') + 1
output_lines = output_lines[results_start:]
elif test_file == 'io_buffer.lamina' and len(output_lines) >= 3:
output_lines = output_lines[-3:]
elif test_file == 'io_types.lamina':
filtered_lines = []
for line in output_lines:
printable_line = ''.join(c for c in line if ord(c) >= 32 and ord(c) <= 126)
if printable_line.strip():
filtered_lines.append(printable_line.strip())
output_lines = filtered_lines
return True, output_lines
def run_tests():
print_colored("๐งช Running Lamina Test Suite", Colors.BOLD + Colors.BLUE)
print_colored("=" * 50, Colors.BLUE)
passed = 0
failed = 0
for test_file, expected_output in TEST_CASES.items():
print(f"\n๐ Testing {test_file}...")
success, result = compile_and_run_test(test_file)
if not success:
print_colored(f"โ FAILED: {result}", Colors.RED)
failed += 1
continue
actual_output = result
if actual_output == expected_output:
print_colored(f"โ
PASSED", Colors.GREEN)
print(f" Output: {actual_output}")
passed += 1
else:
print_colored(f"โ FAILED: Output mismatch", Colors.RED)
print(f" Expected: {expected_output}")
print(f" Actual: {actual_output}")
failed += 1
print_colored("\n" + "=" * 50, Colors.BLUE)
total = passed + failed
if failed == 0:
print_colored(f"๐ All {total} tests PASSED!", Colors.GREEN + Colors.BOLD)
else:
print_colored(f"๐ Results: {passed}/{total} passed, {failed} failed", Colors.YELLOW)
if failed > 0:
sys.exit(1)
def list_tests():
print_colored("๐ Available Test Cases:", Colors.BOLD + Colors.BLUE)
for i, (test_file, expected) in enumerate(TEST_CASES.items(), 1):
print(f"{i:2d}. {test_file:<20} โ {expected}")
def run_single_test(test_name):
if test_name not in TEST_CASES:
print_colored(f"โ Test '{test_name}' not found", Colors.RED)
list_tests()
return
print_colored(f"๐งช Running single test: {test_name}", Colors.BOLD + Colors.BLUE)
success, result = compile_and_run_test(test_name)
expected = TEST_CASES[test_name]
if not success:
print_colored(f"โ FAILED: {result}", Colors.RED)
return
actual_output = result
if actual_output == expected:
print_colored(f"โ
PASSED", Colors.GREEN)
print(f" Output: {actual_output}")
else:
print_colored(f"โ FAILED: Output mismatch", Colors.RED)
print(f" Expected: {expected}")
print(f" Actual: {actual_output}")
if __name__ == "__main__":
if len(sys.argv) > 1:
if sys.argv[1] == "--list":
list_tests()
elif sys.argv[1] == "--help":
print("Usage:")
print(" python run_tests.py # Run all tests")
print(" python run_tests.py --list # List available tests")
print(" python run_tests.py <test> # Run single test")
else:
run_single_test(sys.argv[1])
else:
run_tests()