Skip to content

Instantly share code, notes, and snippets.

@ammkrn
Created June 28, 2025 16:06
Show Gist options
  • Save ammkrn/13ef8b8fe90c33b51eb3067cf5a96ad0 to your computer and use it in GitHub Desktop.
Save ammkrn/13ef8b8fe90c33b51eb3067cf5a96ad0 to your computer and use it in GitHub Desktop.

Revisions

  1. ammkrn created this gist Jun 28, 2025.
    110 changes: 110 additions & 0 deletions test_export.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,110 @@
    #!/usr/bin/env python3
    import os
    import subprocess
    import sys

    def run_all_tests(lean4export_path: str, tests_root: str, lean_proj_dir: str, lean_mod_filename: str):
    if not os.path.isdir(tests_root):
    raise FileNotFoundError(f"Tests root directory not found: {tests_root}")
    if not os.path.isdir(lean_proj_dir):
    raise FileNotFoundError(f"Lean project directory not found: {lean_proj_dir}")
    if not os.path.isfile(lean4export_path) or not os.access(lean4export_path, os.X_OK):
    raise FileNotFoundError(f"lean4export not found or not executable: {lean4export_path}")

    os.chdir(lean_proj_dir)

    lean_mod_filepath = os.path.join(lean_proj_dir, lean_mod_filename)

    original_contents = ""
    if os.path.isfile(lean_mod_filepath):
    with open(lean_mod_filepath, "r") as f:
    original_contents = f.read()

    # Iterate over each entry in the tests_root directory
    for entry in os.listdir(tests_root):
    test_dir = os.path.join(tests_root, entry)
    if not os.path.isdir(test_dir):
    continue # Skip non-directories

    source_path = os.path.join(test_dir, "source")
    export_path = os.path.join(test_dir, "export")

    # Skip this test directory if source file is missing
    if not os.path.isfile(source_path):
    print(f"[WARNING] 'source' not found in {test_dir}, skipping.")
    continue

    # Read the contents of the test's "source" file
    with open(source_path, "r") as f_src:
    source_contents = f_src.read()

    # Overwrite the selected .lean file with the tests's `source`
    with open(lean_mod_filepath, "w") as f_dot_lean:
    f_dot_lean.write(source_contents)

    # Extract module name from lean_mod_filename (remove .lean extension)
    module_name = os.path.splitext(lean_mod_filename)[0]
    exec_args = ["lake", "env", lean4export_path, module_name]

    if "unsafe" in source_contents:
    exec_args.append("--export-unsafe")
    continue
    try:
    subprocess.run(
    ["lake", "build", module_name],
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    check=True
    )
    except subprocess.CalledProcessError as e:
    print(f"[ERROR] Build failed for test '{entry}':")
    print(f" Exit code: {e.returncode}")
    print(f" stderr: {e.stderr.decode().strip()}")
    # Skip running the executable and continue to the next test
    continue

    with open(export_path, "w") as f_out:
    try:
    subprocess.run(
    exec_args,

    stdout=f_out,
    stderr=subprocess.PIPE,
    check=True
    )
    except subprocess.CalledProcessError as e:
    print(f"[ERROR] Test '{entry}' failed when running executable:")
    print(f" Exit code: {e.returncode}")
    print(f" stderr: {e.stderr.decode().strip()}")
    # Continue to next test even if this one fails
    continue

    print(f"[OK] Ran test '{entry}': output written to {export_path}")

    # Restore the original contents of the lean module file
    with open(lean_mod_filepath, "w") as f:
    f.write(original_contents)


    if __name__ == "__main__":
    if len(sys.argv) != 5:
    print("Error: Missing required arguments", file=sys.stderr)
    print(f"Usage: {sys.argv[0]} <lean4export_path> <tests_root> <lean_proj_dir> <lean_mod_filename>", file=sys.stderr)
    print("", file=sys.stderr)
    print("Arguments:", file=sys.stderr)
    print(" lean4export_path - Path to the lean4export executable", file=sys.stderr)
    print(" tests_root - Path to the directory containing test subdirectories (each should contain a `source` file)", file=sys.stderr)
    print(" lean_proj_dir - Path to the scrap Lean project directory", file=sys.stderr)
    print(" lean_mod_filename - Name of the file inside lean_proj_dir to write test cases to", file=sys.stderr)
    sys.exit(1)

    lean4export_path = sys.argv[1]
    tests_root = sys.argv[2]
    lean_proj_dir = sys.argv[3]
    lean_mod_filename = sys.argv[4]

    try:
    run_all_tests(lean4export_path, tests_root, lean_proj_dir, lean_mod_filename)
    except FileNotFoundError as e:
    print(f"Error: {e}", file=sys.stderr)
    sys.exit(1)