feat(tests): add generator tester

This commit is contained in:
2026-06-16 14:35:52 +02:00
parent 591012d059
commit da38cad23d
3 changed files with 77 additions and 10 deletions

View File

@@ -2,6 +2,7 @@ import ast
import shutil import shutil
from dataclasses import dataclass, field from dataclasses import dataclass, field
from pathlib import Path from pathlib import Path
from typing import Optional
from midas.ast.location import Location from midas.ast.location import Location
import midas.ast.python as p import midas.ast.python as p
@@ -44,14 +45,21 @@ class Generator(p.Stmt.Visitor[ast.stmt], p.Expr.Visitor[ast.expr]):
self._alias_count: int = 0 self._alias_count: int = 0
self._scopes: list[Scope] = [] self._scopes: list[Scope] = []
def generate(self, typed_ast: TypedAST, src_path: Path) -> Path: def generate_ast(self, typed_ast: TypedAST, src_path: Path) -> ast.AST:
self.rel_src_path = src_path.relative_to(self.workdir) self.rel_src_path = src_path.relative_to(self.workdir)
self._typed_ast = typed_ast self._typed_ast = typed_ast
body: list[ast.stmt] = self._visit_body(typed_ast.stmts) body: list[ast.stmt] = self._visit_body(typed_ast.stmts)
module = ast.Module(body=body, type_ignores=[]) module = ast.Module(body=body, type_ignores=[])
module = ast.fix_missing_locations(module) module = ast.fix_missing_locations(module)
return module
def generate(
self, typed_ast: TypedAST, src_path: Path, out_path: Optional[Path] = None
) -> Path:
module: ast.AST = self.generate_ast(typed_ast, src_path)
compiled: str = ast.unparse(module) compiled: str = ast.unparse(module)
out_path: Path = (self.build_dir / self.rel_src_path).resolve() if out_path is None:
out_path = (self.build_dir / self.rel_src_path).resolve()
try: try:
_ = out_path.relative_to(self.build_dir) _ = out_path.relative_to(self.build_dir)
except ValueError: except ValueError:

View File

@@ -21,6 +21,10 @@ class Tester(ABC):
@abstractmethod @abstractmethod
def namespace(self) -> str: ... def namespace(self) -> str: ...
@property
def extension(self) -> str:
return "json"
@property @property
def base_dir(self) -> Path: def base_dir(self) -> Path:
return self.CASES_DIR / self.namespace return self.CASES_DIR / self.namespace
@@ -99,7 +103,7 @@ class Tester(ABC):
return True return True
def _result_path(self, test_path: Path) -> Path: def _result_path(self, test_path: Path) -> Path:
return test_path.parent / (test_path.name + ".ref.json") return test_path.parent / (test_path.name + f".ref.{self.extension}")
def _print_diff(self, diff: Iterator[str]): def _print_diff(self, diff: Iterator[str]):
for line in diff: for line in diff:

55
tests/generator.py Normal file
View File

@@ -0,0 +1,55 @@
import ast
from dataclasses import dataclass
from pathlib import Path
from midas.checker.checker import TypeChecker
from midas.checker.diagnostic import DiagnosticType
from midas.generator.generator import Generator
from midas.utils import TypedAST
from tests.base import Tester
@dataclass
class CaseResult:
compiled_ast: ast.AST = ast.Module([], [])
def dumps(self) -> str:
return ast.dump(self.compiled_ast, indent=2)
class GeneratorTester(Tester):
@property
def namespace(self) -> str:
return "generator"
@property
def extension(self) -> str:
return "txt"
def _list_tests(self) -> list[Path]:
return list(self.base_dir.rglob("*.py"))
def _exec_case(self, path: Path) -> CaseResult:
if not path.exists():
raise FileNotFoundError(f"Could not find test '{path}'")
if not path.is_file():
raise TypeError(f"Test '{path}' is not a file")
result: CaseResult = CaseResult()
checker = TypeChecker()
types_path: Path = path.with_suffix(".midas")
if types_path.exists():
checker.import_midas(types_path)
typed_ast: TypedAST = checker.type_check(path)
if not any(d.type == DiagnosticType.ERROR for d in checker.diagnostics):
generator = Generator(workdir=path.parent)
result.compiled_ast = generator.generate_ast(typed_ast, path)
return result
if __name__ == "__main__":
GeneratorTester.main()