463 lines
18 KiB
Python
463 lines
18 KiB
Python
import os
|
|
|
|
import pytest
|
|
from core.builtin_concepts import BuiltinConcepts, ReturnValueConcept, UserInputConcept
|
|
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, ConceptParts
|
|
from core.sheerka.Sheerka import Sheerka, BASE_NODE_PARSER_CLASS
|
|
from core.tokenizer import Token, TokenKind
|
|
|
|
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
|
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
|
|
|
|
|
class ConceptWithGetObjValue(Concept):
|
|
def get_obj_value(self):
|
|
return self.get_value("my_prop")
|
|
|
|
|
|
class TestSheerkaUsingMemoryBasedSheerka(TestUsingMemoryBasedSheerka):
|
|
|
|
def test_i_can_initialize_services(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
assert len(sheerka.services) > 0
|
|
assert None not in sheerka.services
|
|
assert "VariableManager" in sheerka.services # test at least one service
|
|
|
|
def test_i_can_initialize_builtin_parsers(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
# test existence of some parser (not all)
|
|
assert "parsers.DefConceptParser.DefConceptParser" in sheerka.parsers
|
|
assert "parsers.BnfNodeParser.BnfNodeParser" in sheerka.parsers
|
|
assert "parsers.SyaNodeParser.SyaNodeParser" in sheerka.parsers
|
|
assert "parsers.AtomNodeParser.AtomNodeParser" in sheerka.parsers
|
|
|
|
# make sure BaseNodeParser is properly initialized
|
|
assert BASE_NODE_PARSER_CLASS not in sheerka.parsers
|
|
assert sheerka.bnp is not None
|
|
|
|
def test_i_can_list_builtin_concepts(self):
|
|
sheerka = self.get_sheerka()
|
|
builtins = list(sheerka.get_builtins_classes_as_dict())
|
|
|
|
assert str(BuiltinConcepts.ERROR) in builtins
|
|
assert str(BuiltinConcepts.RETURN_VALUE) in builtins
|
|
|
|
def test_i_can_get_a_builtin_concept_by_their_enum_or_the_string(self):
|
|
"""
|
|
Checks that a concept can be found its name
|
|
even when there are variables in the name (ex 'hello + a' or 'a + b' )
|
|
:return:
|
|
"""
|
|
sheerka = self.get_sheerka()
|
|
for key in sheerka.get_builtins_classes_as_dict():
|
|
assert sheerka.get_by_key(key) is not None
|
|
assert sheerka.get_by_key(str(key)) is not None
|
|
|
|
def test_i_cannot_get_when_key_is_none(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
res = sheerka.get_by_key(None)
|
|
assert sheerka.isinstance(res, BuiltinConcepts.ERROR)
|
|
assert res.body == "Concept 'None' is undefined."
|
|
|
|
def test_i_cannot_get_when_key_is_not_found(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
loaded = sheerka.get_by_key("key_that_does_not_exist")
|
|
|
|
assert loaded is not None
|
|
assert sheerka.isinstance(loaded, BuiltinConcepts.UNKNOWN_CONCEPT)
|
|
assert loaded.body == ("key", "key_that_does_not_exist")
|
|
assert loaded.metadata.is_evaluated
|
|
|
|
def test_i_cannot_get_when_id_is_not_found(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
loaded = sheerka.get_by_id("id_that_does_not_exist")
|
|
|
|
assert loaded is not None
|
|
assert sheerka.isinstance(loaded, BuiltinConcepts.UNKNOWN_CONCEPT)
|
|
assert loaded.body == ("id", "id_that_does_not_exist")
|
|
assert loaded.metadata.is_evaluated
|
|
|
|
def test_i_can_instantiate_a_builtin_concept_when_it_has_its_own_class(self):
|
|
sheerka = self.get_sheerka()
|
|
ret = sheerka.new(BuiltinConcepts.RETURN_VALUE, who="who", status="status", value="value", message="message")
|
|
|
|
assert isinstance(ret, ReturnValueConcept)
|
|
assert ret.key == str(BuiltinConcepts.RETURN_VALUE)
|
|
assert ret.who == "who"
|
|
assert ret.status == "status"
|
|
assert ret.value == "value"
|
|
assert ret.message == "message"
|
|
|
|
# check the others
|
|
for key, concept_class in sheerka.get_builtins_classes_as_dict().items():
|
|
assert isinstance(sheerka.get_by_key(key), concept_class)
|
|
|
|
def test_i_can_instantiate_a_builtin_concept_when_no_specific_class(self):
|
|
sheerka = self.get_sheerka()
|
|
ret = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT, body="fake_concept")
|
|
|
|
assert isinstance(ret, Concept)
|
|
assert ret.key == str(BuiltinConcepts.UNKNOWN_CONCEPT)
|
|
assert ret.body == "fake_concept"
|
|
|
|
def test_i_can_instantiate_a_concept(self):
|
|
sheerka, context, concept = self.init_concepts(self.get_default_concept(), create_new=True)
|
|
|
|
new = sheerka.new(concept.key, a=10, b="value")
|
|
|
|
assert sheerka.isinstance(new, concept)
|
|
for prop in PROPERTIES_TO_SERIALIZE:
|
|
assert getattr(new.metadata, prop) == getattr(concept.metadata, prop)
|
|
|
|
assert new.get_value("a") == 10
|
|
assert new.get_value("b") == "value"
|
|
|
|
def test_i_can_instantiate_multiple_when_same_key(self):
|
|
sheerka, context, *concepts = self.init_concepts(
|
|
Concept("foo", body="foo1"),
|
|
Concept("foo", body="foo2"),
|
|
create_new=True)
|
|
|
|
# when no id, i get two instances
|
|
concepts = sheerka.new("foo")
|
|
assert len(concepts) == 2
|
|
assert concepts[0].id == "1001"
|
|
assert concepts[0].metadata.body == "foo1"
|
|
assert concepts[1].id == "1002"
|
|
assert concepts[1].metadata.body == "foo2"
|
|
|
|
# only one instance if the id is given
|
|
foo1 = sheerka.new(("foo", "1001"))
|
|
assert foo1.metadata.body == "foo1"
|
|
|
|
# only one instance if the id is given
|
|
foo2 = sheerka.new(("foo", "1002"))
|
|
assert foo2.metadata.body == "foo2"
|
|
|
|
def test_instances_are_different_when_asking_for_new(self):
|
|
sheerka, context, concept = self.init_concepts(self.get_default_concept(), create_new=True)
|
|
|
|
new1 = sheerka.new(concept.key, a=10, b="value")
|
|
new2 = sheerka.new(concept.key, a=10, b="value")
|
|
|
|
assert new1 == new2
|
|
assert id(new1) != id(new2)
|
|
|
|
def test_new_instance_does_not_impact_each_others(self):
|
|
sheerka, context, foo, bar = self.init_concepts("foo", "bar", create_new=True)
|
|
|
|
new_foo = sheerka.new("foo")
|
|
new_foo.metadata.body = "metadata value" # modify metadata
|
|
new_foo.def_var("var_name", "default value") # modify definition of variables
|
|
new_foo.add_prop(BuiltinConcepts.ISA, bar) # modify property
|
|
new_foo.compiled["var_name"] = "'var value'"
|
|
new_foo.set_value(ConceptParts.BODY, "body value") # modify value
|
|
new_foo.set_value("var_name", "var value") # modify value
|
|
|
|
assert new_foo.metadata.body != foo.metadata.body
|
|
assert new_foo.metadata.variables != foo.metadata.variables
|
|
assert new_foo.metadata.props != foo.metadata.props
|
|
assert new_foo.values != foo.values
|
|
assert new_foo.compiled != foo.compiled
|
|
|
|
def test_i_get_the_same_instance_when_is_unique_is_true(self):
|
|
sheerka, context, concept = self.init_concepts(Concept(name="unique", is_unique=True), create_new=True)
|
|
|
|
new1 = sheerka.new(concept.key)
|
|
new2 = sheerka.new(concept.key, a=10, b="value") # not that variables are simply discareded
|
|
|
|
assert new1 == new2
|
|
assert id(new1) == id(new2)
|
|
|
|
def test_values_are_reset_when_asking_for_a_new_instance(self):
|
|
sheerka, context, template = self.init_concepts(
|
|
Concept("foo", body="'foo body'"),
|
|
create_new=True,
|
|
eval_body=True)
|
|
|
|
sheerka.evaluate_concept(context, sheerka.get_by_id(template.id))
|
|
assert template.metadata.is_evaluated
|
|
assert template.body == "foo body"
|
|
|
|
new = sheerka.new(template.key)
|
|
assert not new.metadata.is_evaluated
|
|
assert new.body == BuiltinConcepts.NOT_INITIALIZED
|
|
|
|
new = sheerka.new((None, template.id))
|
|
assert not new.metadata.is_evaluated
|
|
assert new.body == BuiltinConcepts.NOT_INITIALIZED
|
|
|
|
def test_i_cannot_instantiate_an_unknown_concept(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
new = sheerka.new("fake_concept")
|
|
|
|
assert sheerka.isinstance(new, BuiltinConcepts.UNKNOWN_CONCEPT)
|
|
assert new.body == ('key', 'fake_concept')
|
|
|
|
def test_i_cannot_instantiate_with_invalid_id(self):
|
|
sheerka, context, *concepts = self.init_concepts(
|
|
Concept("foo", body="foo1"),
|
|
Concept("foo", body="foo2"),
|
|
create_new=True)
|
|
|
|
new = sheerka.new(("foo", "invalid_id"))
|
|
|
|
assert sheerka.isinstance(new, BuiltinConcepts.UNKNOWN_CONCEPT)
|
|
assert new.body == [('key', 'foo'), ('id', 'invalid_id')]
|
|
|
|
def test_i_cannot_instantiate_with_invalid_key(self):
|
|
sheerka, context, *concepts = self.init_concepts(
|
|
Concept("foo", body="foo1"),
|
|
Concept("foo", body="foo2"),
|
|
create_new=True)
|
|
|
|
new = sheerka.new(("invalid_key", "1001"))
|
|
|
|
assert sheerka.isinstance(new, BuiltinConcepts.UNKNOWN_CONCEPT)
|
|
assert new.body == [('key', 'invalid_key'), ('id', '1001')]
|
|
|
|
def test_concept_id_is_irrelevant_when_only_one_concept(self):
|
|
sheerka, context, *concepts = self.init_concepts(
|
|
Concept("foo", body="foo1"),
|
|
create_new=True)
|
|
|
|
new = sheerka.new(("foo", "invalid_id"))
|
|
|
|
assert sheerka.isinstance(new, "foo")
|
|
assert new.metadata.body == "foo1"
|
|
|
|
def test_i_cannot_instantiate_when_properties_are_not_recognized(self):
|
|
sheerka, context, concept = self.init_concepts(self.get_default_concept(), create_new=True)
|
|
|
|
new = sheerka.new(concept.key, a=10, c="value")
|
|
|
|
assert sheerka.isinstance(new, BuiltinConcepts.UNKNOWN_PROPERTY)
|
|
assert new.property_name == "c"
|
|
assert sheerka.isinstance(new.concept, concept)
|
|
|
|
@pytest.mark.parametrize("concept, reduce_simple_list, expected", [
|
|
# (None, False, None),
|
|
# (3.14, False, 3.14),
|
|
# ("foo", False, "foo"),
|
|
# (True, False, True),
|
|
# (Concept("name", body="foo"), False, "foo"),
|
|
# (Concept("name"), False, Concept("name")),
|
|
# (ConceptWithGetObjValue("name").set_value("my_prop", "my_value"), False, "my_value"),
|
|
# (ReturnValueConcept(value="return_value"), False, "return_value"),
|
|
# (ReturnValueConcept(value=Concept(key=BuiltinConcepts.USER_INPUT, body="text"), status=True), False, "text"),
|
|
# (ReturnValueConcept(value=UserInputConcept("text"), status=True), False, "text"),
|
|
(ReturnValueConcept(value=Concept("foo", body=False).auto_init(), status=True), False, False),
|
|
(Concept("name", body=["foo", "bar"]), False, ["foo", "bar"]),
|
|
(Concept("name", body=["foo"]), True, "foo"),
|
|
(Concept("name", body=Concept("foo")), False, Concept("foo")),
|
|
(Concept("name", body=Concept("foo", body="value")), False, "value"),
|
|
(Concept("name", body=Concept("foo", body=Concept("bar", body="value"))), False, "value"),
|
|
(Concept("name", body=Concept("foo", body=ReturnValueConcept(value="return_value"))), False, "return_value"),
|
|
])
|
|
def test_i_can_get_value(self, concept, reduce_simple_list, expected):
|
|
sheerka = self.get_sheerka()
|
|
|
|
# I use auto_init() instead of evaluate_concept() to be quicker
|
|
c = concept
|
|
while isinstance(c, Concept):
|
|
c.auto_init()
|
|
c = c.body
|
|
|
|
assert sheerka.objvalue(concept, reduce_simple_list) == expected
|
|
|
|
def test_builtin_error_concept_are_errors(self):
|
|
# only test a random one, it will be the same for the others
|
|
sheerka = self.get_sheerka()
|
|
assert not sheerka.is_success(sheerka.new(BuiltinConcepts.TOO_MANY_SUCCESS))
|
|
|
|
@pytest.mark.parametrize("concept, expected", [
|
|
# by name
|
|
("foo", ["foo", "foo2"]),
|
|
("bar", "bar"),
|
|
("plus", "plus"),
|
|
("a mult b", "mult"),
|
|
|
|
# by tuple
|
|
(("foo", None), ["foo", "foo2"]),
|
|
(("foo", "1002"), "foo2"),
|
|
((None, "1001"), "foo"),
|
|
(("plus", None), "plus"),
|
|
(("1001", None), "1001"),
|
|
|
|
# by token
|
|
(Token(TokenKind.CONCEPT, ("foo", None), 0, 0, 0), ["foo", "foo2"]),
|
|
|
|
# by concept token str
|
|
("c:foo:", ["foo", "foo2"]),
|
|
|
|
# I cannot resolve
|
|
(None, None),
|
|
("unknown", None),
|
|
((None, None), None),
|
|
(("unknown", None), None),
|
|
((None, "unknown"), None),
|
|
(Token(TokenKind.CONCEPT, (None, None), 0, 0, 0), None),
|
|
("c:unknown:", None),
|
|
("c:foo:.id", None),
|
|
("c:foo: + 1", None),
|
|
|
|
])
|
|
def test_i_can_resolve_concept(self, concept, expected):
|
|
sheerka, context, *concepts = self.init_concepts(
|
|
"foo",
|
|
Concept("foo", body="another one"),
|
|
"bar",
|
|
self.from_def_concept("plus", "a plus b", ["a", "b"]),
|
|
Concept("a mult b").def_var("a").def_var("b"),
|
|
Concept("1001"),
|
|
)
|
|
|
|
cmap = {k: concepts[i] for i, k in enumerate(["foo", "foo2", "bar", "plus", "mult", "1001"])}
|
|
cmap[None] = None
|
|
|
|
real_expected = [cmap[e] for e in expected] if isinstance(expected, list) else cmap[expected]
|
|
assert sheerka.resolve(concept) == real_expected
|
|
|
|
def test_i_can_resolve_when_searching_by_definition(self):
|
|
sheerka, context, plus = self.init_concepts(
|
|
self.from_def_concept("plus", "a plus b", ["a", "b"]),
|
|
create_new=True
|
|
)
|
|
|
|
assert sheerka.resolve("a plus b") == plus
|
|
|
|
|
|
class TestSheerkaUsingFileBasedSheerka(TestUsingFileBasedSheerka):
|
|
|
|
def test_root_folder_is_created_after_initialization(self):
|
|
return_value = Sheerka().initialize(self.root_folder)
|
|
assert return_value.status, "initialisation should be successful"
|
|
assert os.path.exists(self.root_folder), "init folder should be created"
|
|
|
|
def test_builtin_concepts_are_initialized(self):
|
|
sheerka = self.get_sheerka()
|
|
for concept_name in BuiltinConcepts:
|
|
assert sheerka.has_key(str(concept_name))
|
|
assert sheerka.sdp.get(sheerka.CONCEPTS_BY_KEY_ENTRY, str(concept_name)) is not None
|
|
|
|
# I can get back data from the sdp when the cache is empty
|
|
sheerka.cache_manager.clear()
|
|
|
|
# caches are empty
|
|
assert not sheerka.has_id("1")
|
|
assert not sheerka.has_key(str(BuiltinConcepts.SHEERKA))
|
|
|
|
assert sheerka.get_by_id("1") == sheerka # use sdp
|
|
|
|
# assert sheerka.has_key(str(BuiltinConcepts.SHEERKA)) # auto update the other caches
|
|
|
|
def test_builtin_concepts_can_be_updated(self):
|
|
sheerka = self.get_sheerka()
|
|
before_parsing = sheerka.get_by_key(BuiltinConcepts.BEFORE_PARSING)
|
|
before_parsing.metadata.desc = "I have a description"
|
|
before_parsing.metadata.full_serialization = True
|
|
with sheerka.sdp.get_transaction("Test") as transac:
|
|
transac.add(sheerka.CONCEPTS_BY_KEY_ENTRY, before_parsing.key, before_parsing, use_ref=True)
|
|
|
|
sheerka = self.get_sheerka() # another fresh new instance
|
|
before_parsing = sheerka.get_by_key(BuiltinConcepts.BEFORE_PARSING)
|
|
|
|
assert before_parsing.metadata.desc == "I have a description"
|
|
|
|
def test_i_first_look_in_local_cache(self):
|
|
sheerka, context, concept = self.init_concepts("foo", create_new=True)
|
|
sheerka.cache_manager.commit(context)
|
|
|
|
sheerka.get_by_key(concept.key).new_property = "I have modified the concept in cache"
|
|
|
|
from_cache = sheerka.get_by_key(concept.key)
|
|
assert from_cache is not None
|
|
assert from_cache.key == concept.key
|
|
assert from_cache.new_property == "I have modified the concept in cache"
|
|
|
|
# sdp instance is not modified
|
|
sheerka.cache_manager.clear()
|
|
from_sdp = sheerka.get_by_key(concept.key)
|
|
assert from_sdp is not None
|
|
assert from_sdp.key == concept.key
|
|
assert not hasattr(from_sdp, "new_property")
|
|
|
|
def test_i_can_retrieve_from_sdp_when_cache_is_reset(self):
|
|
sheerka, context, concept = self.init_concepts(Concept("foo", body="1"))
|
|
sheerka.cache_manager.commit(context)
|
|
|
|
sheerka.cache_manager.clear()
|
|
sheerka.get_by_key("foo")
|
|
assert sheerka.has_key("foo")
|
|
|
|
# It's also updated when sdp returns more than one element
|
|
concept2 = Concept("foo", body="2")
|
|
sheerka.create_new_concept(context, concept2)
|
|
sheerka.cache_manager.commit(context)
|
|
|
|
sheerka.cache_manager.clear()
|
|
assert len(sheerka.get_by_key("foo")) == 2
|
|
assert sheerka.has_key("foo")
|
|
|
|
# updated when by_id
|
|
sheerka.cache_manager.clear()
|
|
assert sheerka.get_by_id("1001") == concept
|
|
assert sheerka.has_id("1001")
|
|
|
|
sheerka.cache_manager.clear()
|
|
assert sheerka.get_by_name("foo") == [concept, concept2]
|
|
assert sheerka.has_name("foo")
|
|
|
|
sheerka.cache_manager.clear()
|
|
assert sheerka.get_by_hash(concept.get_definition_hash()) == concept
|
|
assert sheerka.has_hash(concept.get_definition_hash())
|
|
|
|
def test_get_by_key_retrieve_all_elements(self):
|
|
sheerka, context, *concepts = self.init_concepts(
|
|
Concept("foo", body="1"),
|
|
Concept("foo", body="2"),
|
|
create_new=True)
|
|
sheerka.cache_manager.commit(context)
|
|
|
|
sheerka.cache_manager.clear()
|
|
sheerka.get_by_key("foo", "1001") # I ask only for the one with id = "1001"
|
|
|
|
# but the two keys are returned
|
|
concepts = sheerka.get_by_key("foo")
|
|
assert len(concepts) == 2
|
|
assert concepts[0].id == "1001"
|
|
assert concepts[1].id == "1002"
|
|
|
|
def test_concept_node_parsing_is_initialized_at_startup(self):
|
|
sheerka, context, foo, bar, baz = self.init_concepts(
|
|
"foo",
|
|
"bar",
|
|
Concept("baz", definition="foo"),
|
|
create_new=True)
|
|
sheerka.cache_manager.commit(context)
|
|
|
|
assert sheerka.cache_manager.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
|
|
'bar': ['1002'],
|
|
'c:|1001:': ['1003'],
|
|
'foo': ['1001']}
|
|
assert sheerka.cache_manager.copy(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
|
|
'bar': ['1002'],
|
|
'foo': ['1001', '1003']
|
|
}
|
|
|
|
sheerka = self.get_sheerka() # another instance
|
|
assert sheerka.cache_manager.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
|
|
'bar': ['1002'],
|
|
'c:|1001:': ['1003'],
|
|
'foo': ['1001']}
|
|
assert sheerka.cache_manager.copy(sheerka.RESOLVED_CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {
|
|
'bar': ['1002'],
|
|
'foo': ['1001', '1003']
|
|
}
|