205 lines
8.9 KiB
Python
205 lines
8.9 KiB
Python
import ast
|
|
import pytest
|
|
|
|
from core.builtin_concepts import ReturnValueConcept, ParserResultConcept, BuiltinConcepts
|
|
from core.concept import VARIABLE_PREFIX, Concept, DEFINITION_TYPE_BNF, DEFINITION_TYPE_DEF
|
|
from core.tokenizer import Tokenizer
|
|
from evaluators.AddConceptEvaluator import AddConceptEvaluator
|
|
from parsers.BaseParser import BaseParser
|
|
from parsers.BnfNodeParser import Sequence, StrMatch, ZeroOrMore, ConceptExpression
|
|
from parsers.BnfParser import BnfParser
|
|
from parsers.DefaultParser import DefConceptNode, NameNode
|
|
from parsers.PythonParser import PythonNode, PythonParser
|
|
|
|
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
|
|
|
|
|
class TestAddConceptEvaluator(TestUsingMemoryBasedSheerka):
|
|
|
|
@staticmethod
|
|
def get_concept_part(part):
|
|
if isinstance(part, str):
|
|
node = PythonNode(part, ast.parse(part, mode="eval"))
|
|
return ReturnValueConcept(
|
|
who="parsers.Default",
|
|
status=True,
|
|
value=ParserResultConcept(
|
|
source=part,
|
|
parser=PythonParser(),
|
|
value=node))
|
|
|
|
if isinstance(part, PythonNode):
|
|
return ReturnValueConcept(
|
|
who="parsers.Default",
|
|
status=True,
|
|
value=ParserResultConcept(
|
|
source=part.source,
|
|
parser=PythonParser(),
|
|
value=part))
|
|
|
|
if isinstance(part, ReturnValueConcept):
|
|
return part
|
|
|
|
@staticmethod
|
|
def get_return_value(source, parsing_expression):
|
|
return ReturnValueConcept(
|
|
who="Parsers:RegexParser",
|
|
status=True,
|
|
value=ParserResultConcept(
|
|
source=source,
|
|
parser=BnfParser(),
|
|
value=parsing_expression
|
|
)
|
|
)
|
|
|
|
def get_def_concept(self, name, where=None, pre=None, post=None, body=None, definition=None, bnf_def=None):
|
|
def_concept = DefConceptNode([], name=NameNode(list(Tokenizer(name))))
|
|
|
|
if body:
|
|
def_concept.body = self.get_concept_part(body)
|
|
if where:
|
|
def_concept.where = self.get_concept_part(where)
|
|
if pre:
|
|
def_concept.pre = self.get_concept_part(pre)
|
|
if post:
|
|
def_concept.post = self.get_concept_part(post)
|
|
if bnf_def:
|
|
def_concept.definition = bnf_def
|
|
def_concept.definition_type = DEFINITION_TYPE_BNF
|
|
if definition:
|
|
def_concept.definition = NameNode(list(Tokenizer(definition)))
|
|
def_concept.definition_type = DEFINITION_TYPE_DEF
|
|
|
|
return ReturnValueConcept(BaseParser.PREFIX + "some_name", True, ParserResultConcept(value=def_concept))
|
|
|
|
@pytest.mark.parametrize("ret_val, expected", [
|
|
(ReturnValueConcept(BaseParser.PREFIX + "some_name", True, ParserResultConcept(value=DefConceptNode([]))),
|
|
True),
|
|
(ReturnValueConcept(BaseParser.PREFIX + "some_name", False, ParserResultConcept(value=DefConceptNode([]))),
|
|
False),
|
|
(ReturnValueConcept(BaseParser.PREFIX + "some_name", True, "not a ParserResultConcept"), False),
|
|
(ReturnValueConcept(BaseParser.PREFIX + "some_name", True, ParserResultConcept()), False),
|
|
])
|
|
def test_i_can_match(self, ret_val, expected):
|
|
context = self.get_context()
|
|
assert AddConceptEvaluator().matches(context, ret_val) == expected
|
|
|
|
def test_that_the_source_is_correctly_set_for_bnf_concept(self):
|
|
context = self.get_context()
|
|
def_concept_return_value = self.get_def_concept(
|
|
name="hello a",
|
|
bnf_def=self.get_return_value("hello a", Sequence(StrMatch("hello"), StrMatch("a"))),
|
|
where="isinstance(a, str )",
|
|
pre="a is not None",
|
|
body="print('hello' + a)")
|
|
|
|
evaluated = AddConceptEvaluator().eval(context, def_concept_return_value)
|
|
|
|
assert evaluated.status
|
|
assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT)
|
|
|
|
created_concept = evaluated.body.body
|
|
assert created_concept.metadata.name == "hello a"
|
|
assert created_concept.metadata.key == "hello __var__0"
|
|
assert created_concept.metadata.where == "isinstance(a, str )"
|
|
assert created_concept.metadata.pre == "a is not None"
|
|
assert created_concept.metadata.post is None
|
|
assert created_concept.metadata.body == "print('hello' + a)"
|
|
assert created_concept.metadata.definition == "hello a"
|
|
assert created_concept.metadata.definition_type == "bnf"
|
|
|
|
def test_that_the_source_is_correctly_set_for_concept_with_simple_definition(self):
|
|
context = self.get_context()
|
|
def_concept_return_value = self.get_def_concept(
|
|
name="greetings",
|
|
definition="hello a",
|
|
where="isinstance(a, str )",
|
|
pre="a is not None",
|
|
body="print('hello' + a)")
|
|
|
|
evaluated = AddConceptEvaluator().eval(context, def_concept_return_value)
|
|
|
|
assert evaluated.status
|
|
assert context.sheerka.isinstance(evaluated.body, BuiltinConcepts.NEW_CONCEPT)
|
|
|
|
created_concept = evaluated.body.body
|
|
assert created_concept.metadata.name == "greetings"
|
|
assert created_concept.metadata.key == "hello __var__0"
|
|
assert created_concept.metadata.where == "isinstance(a, str )"
|
|
assert created_concept.metadata.pre == "a is not None"
|
|
assert created_concept.metadata.post is None
|
|
assert created_concept.metadata.body == "print('hello' + a)"
|
|
assert created_concept.metadata.definition == "hello a"
|
|
assert created_concept.metadata.definition_type == "def"
|
|
|
|
def test_that_the_new_concept_is_correctly_saved_in_db(self):
|
|
context = self.get_context()
|
|
def_concept_return_value = self.get_def_concept(
|
|
name="hello a",
|
|
bnf_def=self.get_return_value("hello a", Sequence(StrMatch("hello"), StrMatch("a"))),
|
|
where="isinstance(a, str )",
|
|
pre="a is not None",
|
|
body="print('hello' + a)")
|
|
|
|
# sanity. Make sure that the concept does not already exist
|
|
from_db = context.sheerka.get("hello " + VARIABLE_PREFIX + "0")
|
|
assert context.sheerka.isinstance(from_db, BuiltinConcepts.UNKNOWN_CONCEPT)
|
|
|
|
AddConceptEvaluator().eval(context, def_concept_return_value)
|
|
context.sheerka.concepts_cache = {} # reset cache
|
|
from_db = context.sheerka.get("hello " + VARIABLE_PREFIX + "0")
|
|
|
|
assert from_db.metadata.key == f"hello {VARIABLE_PREFIX}0"
|
|
assert from_db.metadata.name == "hello a"
|
|
assert from_db.metadata.where == "isinstance(a, str )"
|
|
assert from_db.metadata.pre == "a is not None"
|
|
assert from_db.metadata.post is None
|
|
assert from_db.metadata.body == "print('hello' + a)"
|
|
assert from_db.metadata.definition == "hello a"
|
|
assert from_db.metadata.definition_type == "bnf"
|
|
assert len(from_db.metadata.props) == 1
|
|
assert from_db.metadata.props[0] == ("a", None)
|
|
assert "a" in from_db.props
|
|
|
|
assert from_db.compiled == {} # ast is not saved in db
|
|
|
|
def test_i_can_get_props_from_python_node_when_long_name(self):
|
|
ret_val = self.get_concept_part("isinstance(a, str)")
|
|
context = self.get_context()
|
|
|
|
assert AddConceptEvaluator.get_props(context.sheerka, ret_val, ["a", "b"]) == ["a"]
|
|
|
|
def test_i_cannot_get_props_from_python_node_when_name_has_only_one_token(self):
|
|
ret_val = self.get_concept_part("isinstance(a, str)")
|
|
context = self.get_context()
|
|
|
|
assert AddConceptEvaluator.get_props(context.sheerka, ret_val, ["a"]) == []
|
|
|
|
def test_i_can_get_props_from_another_concept(self):
|
|
concept = Concept("hello").def_prop("a").def_prop("b")
|
|
ret_val = ReturnValueConcept(who="some_parser",
|
|
status=True,
|
|
value=ParserResultConcept(value=concept))
|
|
|
|
assert AddConceptEvaluator.get_props(self.get_sheerka(), ret_val, []) == ["a", "b"]
|
|
|
|
def test_i_can_get_props_from_definition(self):
|
|
parsing_expression = Sequence(ConceptExpression('mult'),
|
|
ZeroOrMore(Sequence(StrMatch("+"), ConceptExpression("add"))))
|
|
ret_val = self.get_return_value("mult (('+'|'-') add)?", parsing_expression)
|
|
|
|
assert AddConceptEvaluator.get_props(self.get_sheerka(), ret_val, []) == ["add", "mult"]
|
|
|
|
def test_concept_that_references_itself_is_correctly_created(self):
|
|
context = self.get_context()
|
|
def_concept_as_return_value = self.get_def_concept("foo", body="foo")
|
|
|
|
ret_val = AddConceptEvaluator().eval(context, def_concept_as_return_value)
|
|
|
|
assert ret_val.status
|
|
new_concept = ret_val.body.body
|
|
assert new_concept.name == 'foo'
|
|
assert new_concept.metadata.body == 'foo'
|
|
assert new_concept.props == {}
|
|
assert new_concept.metadata.props == []
|