Files
secondo-py/tests/test_repl.py
2026-01-24 11:30:02 +08:00

221 lines
6.2 KiB
Python

"""
Tests for Phase 4: Query Processing & REPL
"""
from pysecondo.core.nested_list import atom, list_nl
from pysecondo.core.types import BaseType, TupleType, RelationType
from pysecondo.storage.memory import MemoryStorage
from pysecondo.algebras.relation import RelationAlgebra
from pysecondo.algebras.standard import StandardAlgebra
from pysecondo.algebras.base import AlgebraManager
from pysecondo.parser.evaluator import Evaluator
from pysecondo.parser.parser import Parser, parse_query, CreateCommand, UpdateCommand, QueryCommand
import sys
sys.path.insert(0, '.')
def test_parser_create():
"""Test parsing CREATE commands"""
print("Testing Parser (CREATE)...")
parser = Parser()
# Test create command
cmd = parser.parse(
'create cities : (rel (tuple ((Name string)(Population int))))')
assert isinstance(cmd, CreateCommand)
assert cmd.name == "cities"
assert "(rel" in cmd.type_str
print(" ✓ CREATE parsing tests passed")
def test_parser_update():
"""Test parsing UPDATE commands"""
print("Testing Parser (UPDATE)...")
parser = Parser()
# Test update command
cmd = parser.parse(
'update cities := (("Beijing" 21540000)("Shanghai" 24280000))')
assert isinstance(cmd, UpdateCommand)
assert cmd.name == "cities"
assert "Beijing" in cmd.value
print(" ✓ UPDATE parsing tests passed")
def test_parser_query():
"""Test parsing QUERY commands"""
print("Testing Parser (QUERY)...")
parser = Parser()
# Test query command
cmd = parser.parse('query cities feed count')
assert isinstance(cmd, QueryCommand)
assert cmd.expression == "cities feed count"
# Test arithmetic query
cmd = parser.parse('query 5 + 3')
assert isinstance(cmd, QueryCommand)
assert cmd.expression == "5 + 3"
print(" ✓ QUERY parsing tests passed")
def test_parser_expressions():
"""Test expression tokenization"""
print("Testing Expression Tokenization...")
parser = Parser()
# Simple identifier
tokens = parser.parse_expression("cities")
assert tokens == ["cities"]
# Operator chain
tokens = parser.parse_expression("cities feed consume")
assert tokens == ["cities", "feed", "consume"]
# Arithmetic
tokens = parser.parse_expression("5 + 3")
assert tokens == ["5", "+", "3"]
# Complex expression
tokens = parser.parse_expression("cities feed filter true consume")
assert tokens == ["cities", "feed", "filter", "true", "consume"]
print(" ✓ Expression tokenization tests passed")
def test_evaluator_arithmetic():
"""Test evaluating arithmetic expressions"""
print("Testing Evaluator (Arithmetic)...")
storage = MemoryStorage()
algebra_manager = AlgebraManager()
algebra_manager.register_algebra("StandardAlgebra", StandardAlgebra())
evaluator = Evaluator(algebra_manager, storage)
# Test: 5 + 3
tokens = ["5", "+", "3"]
value, value_type = evaluator.evaluate(tokens)
assert value.value == 8
# Test: 10 - 4
tokens = ["10", "-", "4"]
value, value_type = evaluator.evaluate(tokens)
assert value.value == 6
# Test: 6 * 7
tokens = ["6", "*", "7"]
value, value_type = evaluator.evaluate(tokens)
assert value.value == 42
print(" ✓ Arithmetic evaluation tests passed")
def test_evaluator_identifiers():
"""Test evaluating identifiers"""
print("Testing Evaluator (Identifiers)...")
storage = MemoryStorage()
algebra_manager = AlgebraManager()
algebra_manager.register_algebra("StandardAlgebra", StandardAlgebra())
evaluator = Evaluator(algebra_manager, storage)
# Store a value
storage.create_object("x", atom(42), BaseType.INT)
# Test: x
tokens = ["x"]
value, value_type = evaluator.evaluate(tokens)
assert value.value == 42
print(" ✓ Identifier evaluation tests passed")
def test_evaluator_relations():
"""Test evaluating relation expressions"""
print("Testing Evaluator (Relations)...")
storage = MemoryStorage()
algebra_manager = AlgebraManager()
algebra_manager.register_algebra("StandardAlgebra", StandardAlgebra())
algebra_manager.register_algebra(
"RelationAlgebra", RelationAlgebra(storage))
evaluator = Evaluator(algebra_manager, storage)
# Create a relation
cities_type = RelationType(TupleType([]))
storage.create_object("cities", list_nl(), cities_type)
# Test: cities feed
tokens = ["cities", "feed"]
value, value_type = evaluator.evaluate(tokens)
print(" ✓ Relation evaluation tests passed")
def test_end_to_end():
"""Test end-to-end query execution"""
print("Testing End-to-End Queries...")
storage = MemoryStorage()
algebra_manager = AlgebraManager()
algebra_manager.register_algebra("StandardAlgebra", StandardAlgebra())
algebra_manager.register_algebra(
"RelationAlgebra", RelationAlgebra(storage))
parser = Parser()
evaluator = Evaluator(algebra_manager, storage)
# Create relation
create_cmd = parser.parse(
'create cities : (rel (tuple ((Name string)(Population int))))')
assert isinstance(create_cmd, CreateCommand)
# Insert data (using storage directly for simplicity)
from pysecondo.core.types import parse_type
cities_type = parse_type('(rel (tuple ((Name string)(Population int))))')
cities_data = list_nl(
list_nl("Beijing", 21540000),
list_nl("Shanghai", 24280000),
list_nl("Guangzhou", 14040000),
)
storage.create_object("cities", cities_data, cities_type)
# Query: cities feed count
query_cmd = parser.parse('query cities feed count')
assert isinstance(query_cmd, QueryCommand)
tokens = parser.parse_expression(query_cmd.expression)
value, value_type = evaluator.evaluate(tokens)
assert value.value == 3
print(" ✓ End-to-end query tests passed")
if __name__ == "__main__":
print("=" * 50)
print("Phase 4: Query Processing & REPL Tests")
print("=" * 50)
test_parser_create()
test_parser_update()
test_parser_query()
test_parser_expressions()
test_evaluator_arithmetic()
test_evaluator_identifiers()
test_evaluator_relations()
test_end_to_end()
print("\n" + "=" * 50)
print("All Phase 4 tests passed! ✓")
print("=" * 50)