"""Generator regression checks for the designated remote validation environment.""" from pathlib import Path import json import re import unittest from generate_ast import generate, parse_schema, recursive_edges SCHEMA = (Path(__file__).resolve().parents[1] / "crates/frontend/Endor.asdl").read_text(encoding="utf-8") class AstGenerationTests(unittest.TestCase): def test_editor_walkers_only_call_declared_functions(self): editor = generate(SCHEMA)["crates/frontend/editor/ast.ts"] declared = set(re.findall(r"export function (walk\w+)\(", editor)) calls = set(re.findall(r"\b(walk\w+)\(", editor)) self.assertLessEqual(calls, declared) self.assertIn("walkSpan(node.span, visitor)", editor) def test_schema_changes_reach_all_languages_and_schema_identity(self): before = generate(SCHEMA) after = generate(SCHEMA.replace("UnaryOp = Negate", "UnaryOp = Negate | LogicalNot")) self.assertIn("LogicalNot", after["crates/frontend/src/ast/generated.rs"]) self.assertIn('"LogicalNot"', after["crates/frontend/editor/ast.ts"]) editor_schema = json.loads(after["crates/frontend/editor/ast.schema.json"]) self.assertIn("LogicalNot", editor_schema["$defs"]["UnaryOp"]["enum"]) self.assertNotEqual(before["crates/frontend/src/ast/generated.rs"], after["crates/frontend/src/ast/generated.rs"]) self.assertEqual(after, generate(SCHEMA.replace("UnaryOp = Negate", "UnaryOp = Negate | LogicalNot"))) def test_recursive_optional_nodes_are_boxed_and_walked(self): extended = SCHEMA.rsplit("}", 1)[0] + "Link = (Link? next)\n}" outputs = generate(extended) self.assertIn("pub next: Option>", outputs["crates/frontend/src/ast/generated.rs"]) self.assertIn("visitor.visit_link(value)?", outputs["crates/frontend/src/ast/visitor.rs"]) self.assertIn("next?: Link | null", outputs["crates/frontend/editor/ast.ts"]) definitions = parse_schema(SCHEMA) self.assertIn(("ExprKind", "Expr"), recursive_edges(definitions)) self.assertNotIn(("Expr", "ExprKind"), recursive_edges(definitions)) def test_invalid_schemas_fail_instead_of_emitting_partial_types(self): for schema in [ "module Endor { Root = (Missing value) }", "module Endor { Root = (string x, string x) }", "module Endor { Root = A | A }", "module Endor { Root = A Root = B }", "module Endor { Root = (string value", "module Endor { Root = A } trailing", "module Endor { Root = @ }", ]: with self.subTest(schema=schema), self.assertRaises(ValueError): parse_schema(schema) if __name__ == "__main__": unittest.main()