Files
foreignthon-core/tests/test_engine.py
KeshavAnandCode d727e3d51e
All checks were successful
CI / test (push) Successful in 11s
added test and a test json
2026-05-19 15:56:42 -05:00

155 lines
4.5 KiB
Python

from __future__ import annotations
import ast
import json
import textwrap
from pathlib import Path
import pytest
from foreignthon.transpiler import _check_shebang, _detect_lang, detranspile, transpile
# ---------------------------------------------------------------------------
# Setup: Load the local test JSON fixture
# ---------------------------------------------------------------------------
TEST_PACK_PATH = Path(__file__).parent / "test_pack.json"
TEST_PACK = json.loads(TEST_PACK_PATH.read_text(encoding="utf-8"))
def core_transpile(src: str) -> str:
# We pass "es" to match the JSON's meta code, but we feed it the local pack
return transpile(textwrap.dedent(src).strip() + "\n", "es", pack=TEST_PACK)
def core_detranspile(src: str, postfix: bool = False) -> str:
return detranspile(
textwrap.dedent(src).strip() + "\n", "es", postfix=postfix, pack=TEST_PACK
)
def valid(src: str) -> bool:
try:
ast.parse(src)
return True
except SyntaxError:
return False
# ---------------------------------------------------------------------------
# 1. Core Mechanics: Translation & AST Validity
# ---------------------------------------------------------------------------
def test_engine_basic_translation():
# Ensures the engine reads the dictionary and swaps the words
src = """
para i en dist(5):
escribir(i)
"""
out = core_transpile(src)
assert "for" in out and "in" in out and "range" in out and "print" in out
assert valid(out)
# ---------------------------------------------------------------------------
# 2. Core Mechanics: Safety Boundaries (Strings & Comments)
# ---------------------------------------------------------------------------
def test_engine_preserves_strings():
# The engine MUST NOT translate keywords hidden inside strings
out = core_transpile('mensaje = "si para mientras def clase"')
assert '"si para mientras def clase"' in out
def test_engine_preserves_comments():
# The engine MUST NOT translate keywords hidden in comments
out = core_transpile("# si para mientras\nx = 1")
assert "# si para mientras" in out
def test_engine_preserves_fstrings():
out = core_transpile('escribir(f"valor si={42}")')
assert "si" in out # 'si' survives because it is inside the string
# ---------------------------------------------------------------------------
# 3. Core Mechanics: Postfix Syntax (@@)
# ---------------------------------------------------------------------------
def test_engine_postfix_reversal():
# Tests the engine's ability to move the keyword to the front
src = """
x = 5
x > 0 @@si:
escribir(x)
"""
out = core_transpile(src)
assert "if x > 0:" in out
assert "@@" not in out
assert valid(out)
def test_engine_mixed_prefix_postfix():
src = """
si x > 0:
escribir(x)
y < 0 @@si:
escribir(y)
"""
out = core_transpile(src)
assert out.count("if") == 2
assert "@@" not in out
# ---------------------------------------------------------------------------
# 4. Core Mechanics: Decompilation (Round Trip)
# ---------------------------------------------------------------------------
def test_engine_detranspile():
# Standard Python should turn back into foreignthon syntax
src = """
if x > 0:
pass
"""
out = core_detranspile(src)
assert "si" in out and "pasar" in out
def test_engine_roundtrip():
# foreignthon -> Python -> foreignthon
original = "para i en dist(5):\n escribir(i)\n"
compiled = core_transpile(original)
assert valid(compiled)
back = core_detranspile(compiled)
assert "para" in back and "dist" in back
# Accept either valid translation for 'print'
assert "escribir" in back or "imprimir" in back
# ---------------------------------------------------------------------------
# 5. Core Utilities: Detection & Shebangs
# ---------------------------------------------------------------------------
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"))
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"