import subprocess
from pathlib import Path
import difflib
import sys
def normalize_output(content):
lines = content.strip().splitlines()
normalized_lines = [line.strip() for line in lines if line.strip()]
return '\n'.join(normalized_lines)
def test_codegen(test_name):
source = Path(f"tests/codegen/{test_name}.rsc")
expected_babel = Path(f"tests/codegen/expected/{test_name}.babel.js")
expected_swc = Path(f"tests/codegen/expected/{test_name}.swc.rs")
if not source.exists():
return False, f"Source file not found: {source}"
if not expected_babel.exists():
return False, f"Expected Babel output not found: {expected_babel}"
if not expected_swc.exists():
return False, f"Expected SWC output not found: {expected_swc}"
temp_dir = Path("dist_temp")
temp_dir.mkdir(exist_ok=True)
try:
result = subprocess.run(
["cargo", "run", "--bin", "reluxscript", "--",
"build", str(source), "--output", str(temp_dir)],
capture_output=True,
text=True,
timeout=30
)
if result.returncode != 0:
return False, f"Build failed:\n{result.stderr}"
babel_out = temp_dir / "index.js"
swc_out = temp_dir / "lib.rs"
if not babel_out.exists() or not swc_out.exists():
return False, "Output files not generated"
actual_babel = normalize_output(babel_out.read_text())
actual_swc = normalize_output(swc_out.read_text())
expected_babel_content = normalize_output(expected_babel.read_text())
expected_swc_content = normalize_output(expected_swc.read_text())
babel_match = actual_babel == expected_babel_content
swc_match = actual_swc == expected_swc_content
if not babel_match or not swc_match:
errors = []
if not babel_match:
diff = list(difflib.unified_diff(
expected_babel_content.splitlines(keepends=True),
actual_babel.splitlines(keepends=True),
fromfile="expected (Babel)",
tofile="actual (Babel)",
lineterm=""
))
errors.append("Babel output mismatch:\n" + "".join(diff))
if not swc_match:
diff = list(difflib.unified_diff(
expected_swc_content.splitlines(keepends=True),
actual_swc.splitlines(keepends=True),
fromfile="expected (SWC)",
tofile="actual (SWC)",
lineterm=""
))
errors.append("SWC output mismatch:\n" + "".join(diff))
return False, "\n\n".join(errors)
return True, None
except Exception as e:
return False, f"Error: {str(e)}"
finally:
if temp_dir.exists():
for f in temp_dir.glob("*"):
f.unlink()
temp_dir.rmdir()
def main():
tests = [
"unit_literal",
"try_operator",
"block_expr",
"tuple_destruct",
"closure_block",
"parser_module",
"test_hooks",
]
print("Testing codegen output...")
print("=" * 80)
passed = 0
failed = 0
for i, test in enumerate(tests, 1):
print(f"\n[{i}/{len(tests)}] {test} ... ", end="", flush=True)
success, error = test_codegen(test)
if success:
print("PASSED")
passed += 1
else:
print("FAILED")
if error:
print(f"\n{error}\n")
failed += 1
print("\n" + "=" * 80)
print(f"Results: {passed} passed, {failed} failed out of {len(tests)} total")
if failed == 0:
print("\nAll codegen tests passed!")
return 0
else:
print(f"\n{failed} test(s) failed")
return 1
if __name__ == "__main__":
exit(main())