From ac745dd4a6c134e3961042a904304c020aaf53e2 Mon Sep 17 00:00:00 2001 From: KeshavAnandCode Date: Fri, 15 May 2026 18:53:00 -0500 Subject: [PATCH] v1 done --- README.md | 1 + pyproject.toml | 1 - tests/test_transpiler.py | 104 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..ddf7cda --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# foreignthon diff --git a/pyproject.toml b/pyproject.toml index 8705b67..7a74077 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,6 @@ build-backend = "hatchling.build" name = "foreignthon" version = "0.1.0" description = "Write Python in any language. Transpiles foreign-language .xx.py files to standard Python." -readme = "README.md" license = { text = "MIT" } requires-python = ">=3.9" authors = [ diff --git a/tests/test_transpiler.py b/tests/test_transpiler.py index e69de29..b67a4b1 100644 --- a/tests/test_transpiler.py +++ b/tests/test_transpiler.py @@ -0,0 +1,104 @@ +from __future__ import annotations + +import ast +from pathlib import Path + +import pytest + +from foreignthon.transpiler import transpile, _detect_lang, _check_shebang + +# --------------------------------------------------------------------------- +# All tests use the real foreignthon-es pack — no mocks +# --------------------------------------------------------------------------- + +def es(source: str) -> str: + return transpile(source, "es") + + +# --------------------------------------------------------------------------- +# Keywords +# --------------------------------------------------------------------------- + +def test_if_else(): + out = es("si x > 0:\n imprimir(x)\nsino:\n pasar") + assert "if" in out and "else" in out and "pass" in out + assert "si" not in out and "sino" not in out + +def test_for_loop(): + out = es("para i en rango(10):\n imprimir(i)") + assert "for" in out and "in" in out and "range" in out + +def test_function_def(): + out = es("definir saludar(nombre):\n retornar nombre") + assert "def" in out and "return" in out + +def test_class_def(): + out = es("clase Animal:\n pasar") + assert "class" in out and "pass" in out + +def test_booleans_and_none(): + out = es("x = Verdadero\ny = Falso\nz = Nada") + assert "True" in out and "False" in out and "None" in out + +def test_try_except(): + out = es( + "intentar:\n" + " imprimir(x)\n" + "excepto ErrorDeValor:\n" + " pasar\n" + "finalmente:\n" + " pasar" + ) + assert "try" in out and "except" in out and "finally" in out + assert "ValueError" in out + +# --------------------------------------------------------------------------- +# Safety — strings and comments must never be touched +# --------------------------------------------------------------------------- + +def test_strings_not_transpiled(): + out = es('x = "si esto es para mientras definir"') + assert '"si esto es para mientras definir"' in out + +def test_comments_not_transpiled(): + out = es("# si para mientras\nx = 1") + assert "# si para mientras" in out + +def test_fstring_not_touched(): + out = es('imprimir(f"si {x} para")') + assert "si" in out # inside the string, untouched + +# --------------------------------------------------------------------------- +# Output is always valid Python +# --------------------------------------------------------------------------- + +def test_output_is_valid_python(): + out = es( + "definir sumar(a, b):\n" + " retornar a + b\n\n" + "para i en rango(5):\n" + " imprimir(sumar(i, 1))\n" + ) + ast.parse(out) # raises if invalid + +# --------------------------------------------------------------------------- +# Language detection +# --------------------------------------------------------------------------- + +def test_detect_lang_from_extension(): + assert _detect_lang(Path("script.es.py")) == "es" + assert _detect_lang(Path("script.ta.py")) == "ta" + +def test_detect_lang_bad_extension(): + with pytest.raises(ValueError): + _detect_lang(Path("script.py")) + +# --------------------------------------------------------------------------- +# Shebang override +# --------------------------------------------------------------------------- + +def test_shebang_override(): + assert _check_shebang("# foreignthon: fr\nsi x:\n pasar", "es") == "fr" + +def test_shebang_default_when_absent(): + assert _check_shebang("si x:\n pasar", "es") == "es"