Added syntax colorization. Remove all references to deprecated lark_to_lezer module.
This commit is contained in:
@@ -1,172 +0,0 @@
|
||||
"""Tests for lark_to_lezer module."""
|
||||
|
||||
import pytest
|
||||
|
||||
from myfasthtml.core.dsl.lark_to_lezer import (
|
||||
extract_completions_from_grammar,
|
||||
lark_to_lezer_grammar,
|
||||
)
|
||||
|
||||
# Sample grammars for testing
|
||||
SIMPLE_GRAMMAR = r'''
|
||||
start: rule+
|
||||
rule: "if" condition
|
||||
condition: "value" operator literal
|
||||
operator: "==" -> op_eq
|
||||
| "!=" -> op_ne
|
||||
| "contains" -> op_contains
|
||||
literal: QUOTED_STRING -> string_literal
|
||||
| BOOLEAN -> boolean_literal
|
||||
QUOTED_STRING: /"[^"]*"/
|
||||
BOOLEAN: "True" | "False"
|
||||
'''
|
||||
|
||||
GRAMMAR_WITH_KEYWORDS = r'''
|
||||
start: scope+
|
||||
scope: "column" NAME ":" rule
|
||||
| "row" INTEGER ":" rule
|
||||
| "cell" cell_ref ":" rule
|
||||
rule: style_expr condition?
|
||||
condition: "if" "not"? comparison
|
||||
comparison: operand "and" operand
|
||||
| operand "or" operand
|
||||
style_expr: "style" "(" args ")"
|
||||
operand: "value" | literal
|
||||
'''
|
||||
|
||||
GRAMMAR_WITH_TYPES = r'''
|
||||
format_type: "number" -> fmt_number
|
||||
| "date" -> fmt_date
|
||||
| "boolean" -> fmt_boolean
|
||||
| "text" -> fmt_text
|
||||
| "enum" -> fmt_enum
|
||||
'''
|
||||
|
||||
|
||||
class TestExtractCompletions:
|
||||
"""Tests for extract_completions_from_grammar function."""
|
||||
|
||||
def test_i_can_extract_keywords_from_grammar(self):
|
||||
"""Test that keywords like if, not, and are extracted."""
|
||||
completions = extract_completions_from_grammar(GRAMMAR_WITH_KEYWORDS)
|
||||
|
||||
assert "if" in completions["keywords"]
|
||||
assert "not" in completions["keywords"]
|
||||
assert "column" in completions["keywords"]
|
||||
assert "row" in completions["keywords"]
|
||||
assert "cell" in completions["keywords"]
|
||||
assert "value" in completions["keywords"]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"operator",
|
||||
["==", "!=", "contains"],
|
||||
)
|
||||
def test_i_can_extract_operators_from_grammar(self, operator):
|
||||
"""Test that operators are extracted from grammar."""
|
||||
completions = extract_completions_from_grammar(SIMPLE_GRAMMAR)
|
||||
|
||||
assert operator in completions["operators"]
|
||||
|
||||
def test_i_can_extract_functions_from_grammar(self):
|
||||
"""Test that function-like constructs are extracted."""
|
||||
completions = extract_completions_from_grammar(GRAMMAR_WITH_KEYWORDS)
|
||||
|
||||
assert "style" in completions["functions"]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"type_name",
|
||||
["number", "date", "boolean", "text", "enum"],
|
||||
)
|
||||
def test_i_can_extract_types_from_grammar(self, type_name):
|
||||
"""Test that type names are extracted from format_type rule."""
|
||||
completions = extract_completions_from_grammar(GRAMMAR_WITH_TYPES)
|
||||
|
||||
assert type_name in completions["types"]
|
||||
|
||||
@pytest.mark.parametrize("literal", [
|
||||
"True",
|
||||
"False"
|
||||
])
|
||||
def test_i_can_extract_literals_from_grammar(self, literal):
|
||||
"""Test that literal values like True/False are extracted."""
|
||||
completions = extract_completions_from_grammar(SIMPLE_GRAMMAR)
|
||||
|
||||
assert literal in completions["literals"]
|
||||
|
||||
def test_i_can_extract_completions_returns_all_categories(self):
|
||||
"""Test that all completion categories are present in result."""
|
||||
completions = extract_completions_from_grammar(SIMPLE_GRAMMAR)
|
||||
|
||||
assert "keywords" in completions
|
||||
assert "operators" in completions
|
||||
assert "functions" in completions
|
||||
assert "types" in completions
|
||||
assert "literals" in completions
|
||||
|
||||
def test_i_can_extract_completions_returns_sorted_lists(self):
|
||||
"""Test that completion lists are sorted alphabetically."""
|
||||
completions = extract_completions_from_grammar(SIMPLE_GRAMMAR)
|
||||
|
||||
for category in completions.values():
|
||||
assert category == sorted(category)
|
||||
|
||||
|
||||
class TestLarkToLezerConversion:
|
||||
"""Tests for lark_to_lezer_grammar function."""
|
||||
|
||||
def test_i_can_convert_simple_grammar_to_lezer(self):
|
||||
"""Test that a simple Lark grammar is converted to Lezer format."""
|
||||
lezer = lark_to_lezer_grammar(SIMPLE_GRAMMAR)
|
||||
|
||||
# Should have @top directive
|
||||
assert "@top Start" in lezer
|
||||
# Should have @tokens block
|
||||
assert "@tokens {" in lezer
|
||||
# Should have @skip directive
|
||||
assert "@skip {" in lezer
|
||||
|
||||
def test_i_can_convert_rule_names_to_pascal_case(self):
|
||||
"""Test that snake_case rule names become PascalCase."""
|
||||
grammar = r'''
|
||||
my_rule: other_rule
|
||||
other_rule: "test"
|
||||
'''
|
||||
lezer = lark_to_lezer_grammar(grammar)
|
||||
|
||||
assert "MyRule" in lezer
|
||||
assert "OtherRule" in lezer
|
||||
|
||||
def test_i_cannot_include_internal_rules_in_lezer(self):
|
||||
"""Test that rules starting with _ are not included."""
|
||||
grammar = r'''
|
||||
start: rule _NL
|
||||
rule: "test"
|
||||
_NL: /\n/
|
||||
'''
|
||||
lezer = lark_to_lezer_grammar(grammar)
|
||||
|
||||
# Internal rules should not appear as Lezer rules
|
||||
assert "Nl {" not in lezer
|
||||
|
||||
def test_i_can_convert_terminal_regex_to_lezer(self):
|
||||
"""Test that terminal regex patterns are converted."""
|
||||
grammar = r'''
|
||||
NAME: /[a-zA-Z_][a-zA-Z0-9_]*/
|
||||
'''
|
||||
lezer = lark_to_lezer_grammar(grammar)
|
||||
|
||||
assert "NAME" in lezer
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"terminal,pattern",
|
||||
[
|
||||
('BOOLEAN: "True" | "False"', "BOOLEAN"),
|
||||
('KEYWORD: "if"', "KEYWORD"),
|
||||
],
|
||||
)
|
||||
def test_i_can_convert_terminal_strings_to_lezer(self, terminal, pattern):
|
||||
"""Test that terminal string literals are converted."""
|
||||
grammar = f"start: test\n{terminal}"
|
||||
lezer = lark_to_lezer_grammar(grammar)
|
||||
|
||||
assert pattern in lezer
|
||||
Reference in New Issue
Block a user