372 lines
17 KiB
Python
372 lines
17 KiB
Python
import pytest
|
|
|
|
from base import BaseTest
|
|
from common.global_symbols import NotFound, NotInit
|
|
from conftest import NewOntology
|
|
from core.BuiltinConcepts import BuiltinConcepts
|
|
from core.concept import ConceptMetadata
|
|
from core.error import ErrorContext
|
|
from helpers import get_concept, get_concepts, get_metadata
|
|
from services.SheerkaConceptManager import ConceptAlreadyDefined, ConceptManager, ConceptRef
|
|
|
|
|
|
class TestConceptManager(BaseTest):
|
|
|
|
@pytest.fixture()
|
|
def service(self, sheerka):
|
|
return sheerka.services[ConceptManager.NAME]
|
|
|
|
def test_i_can_compute_concept_digest(self, service):
|
|
"""
|
|
Two concepts with the same definition share the same digest
|
|
:return:
|
|
:rtype:
|
|
"""
|
|
metadata = get_metadata("foo", "body")
|
|
digest = service.compute_metadata_digest(metadata)
|
|
assert digest == "7c0f1708968e0312be622950d3f21d588f718f7ba568054ece64d077052a6476"
|
|
|
|
another_metadata = get_metadata("foo", "body")
|
|
other_digest = service.compute_metadata_digest(another_metadata)
|
|
|
|
assert digest == other_digest
|
|
|
|
def test_id_is_not_part_of_the_digest(self, service):
|
|
metadata1 = get_metadata("foo", "body", id=1)
|
|
metadata2 = get_metadata("foo", "body", id=2)
|
|
|
|
assert service.compute_metadata_digest(metadata1) == service.compute_metadata_digest(metadata2)
|
|
|
|
def test_i_can_compute_concept_attributes_based_on_the_metadata(self, service):
|
|
compute_all_attrs = service.compute_all_attrs
|
|
|
|
m1 = get_metadata("foo")
|
|
assert compute_all_attrs(m1.variables) == ('#where#', '#pre#', '#post#', '#body#', '#ret#')
|
|
|
|
m2 = get_metadata("bar", variables=[("var1", None), ("var2", None)])
|
|
assert compute_all_attrs(m2.variables) == ('#where#', '#pre#', '#post#', '#body#', '#ret#', 'var1', 'var2')
|
|
|
|
@pytest.mark.parametrize("definition, variables, expected", [
|
|
("foo", [], "foo"),
|
|
("foo(bar)", [], "foo ( bar )"),
|
|
("foo a", ["a"], "foo __var__0"),
|
|
("a foo b", ["a", "b"], "__var__0 foo __var__1"),
|
|
("a foo b", ["b", "a"], "__var__1 foo __var__0"),
|
|
("foo", ["foo"], "foo"),
|
|
("foo a", ["foo"], "__var__0 a"),
|
|
("foo a b", ["a"], "foo __var__0 b"),
|
|
("'foo'", [], "'foo'"),
|
|
("my name is a", ["a"], "my name is __var__0"),
|
|
("a b c d", ["b", "c"], "a __var__0 __var__1 d"),
|
|
("a 'b c' d", ["b", "c"], "a 'b c' d"),
|
|
("a | b", ["a", "b"], "__var__0 | __var__1"),
|
|
("a b a c", ["a", "b"], "__var__0 __var__1 __var__0 c"),
|
|
("a b a c", ["b", "a"], "__var__1 __var__0 __var__1 c"),
|
|
("def concept a", ["a"], "def concept __var__0"),
|
|
])
|
|
def test_i_can_create_concept_key(self, service, definition, variables, expected):
|
|
expanded_variables = tuple((v, NotInit) for v in variables)
|
|
key = service.create_concept_key(definition, None, expanded_variables)
|
|
|
|
assert key == expected
|
|
|
|
def test_the_key_is_created_from_the_definition_if_it_is_set(self, service):
|
|
assert service.create_concept_key("from name", "from definition", None) == "from definition"
|
|
assert service.create_concept_key("from name", None, None) == "from name"
|
|
|
|
def test_i_can_define_a_new_concept(self, context, service):
|
|
with NewOntology(context, "test_i_can_define_a_new_concept"):
|
|
res = service.define_new_concept(context, "name", body="body")
|
|
|
|
assert res.status is True
|
|
|
|
metadata = res.value.metadata
|
|
assert isinstance(metadata, ConceptMetadata)
|
|
assert metadata.id == "1001"
|
|
assert metadata.name == "name"
|
|
assert metadata.key == "name"
|
|
assert metadata.body == "body"
|
|
assert metadata.digest == "f32363f42e698b1642c8f76f969d76d56f53f0e0732cb651e3360e3ede7b2b11"
|
|
assert metadata.all_attrs == ('#where#', '#pre#', '#post#', '#body#', '#ret#')
|
|
|
|
# is sorted in db
|
|
om = context.sheerka.om
|
|
assert om.get(ConceptManager.CONCEPTS_BY_ID_ENTRY, metadata.id) == metadata
|
|
assert om.get(ConceptManager.CONCEPTS_BY_NAME_ENTRY, metadata.name) == metadata
|
|
assert om.get(ConceptManager.CONCEPTS_BY_KEY_ENTRY, metadata.key) == metadata
|
|
assert om.get(ConceptManager.CONCEPTS_BY_HASH_ENTRY, metadata.digest) == metadata
|
|
|
|
# check first token
|
|
assert om.get(ConceptManager.CONCEPT_BY_FIRST_TOKEN_IN_KEY, "name") == ["1001"]
|
|
|
|
def test_i_can_define_a_new_concept_with_variables(self, context, service):
|
|
with NewOntology(context, "test_i_can_define_a_new_concept_with_variables"):
|
|
res = service.define_new_concept(context,
|
|
name="a multiplied by b",
|
|
variables=[("a", NotInit), ("b", NotInit)])
|
|
|
|
metadata = res.value.metadata
|
|
assert isinstance(metadata, ConceptMetadata)
|
|
assert metadata.id == "1001"
|
|
assert metadata.name == "a multiplied by b"
|
|
assert metadata.key == "__var__0 multiplied by __var__1"
|
|
assert metadata.digest == "17d2360d82fc4264e2bcb75e4aa30ee3de87531acee72f5d939e23bff246b2dd"
|
|
assert metadata.all_attrs == ('#where#', '#pre#', '#post#', '#body#', '#ret#', "a", "b")
|
|
|
|
# is sorted in db
|
|
om = context.sheerka.om
|
|
assert om.get(ConceptManager.CONCEPTS_BY_ID_ENTRY, metadata.id) == metadata
|
|
assert om.get(ConceptManager.CONCEPTS_BY_NAME_ENTRY, metadata.name) == metadata
|
|
assert om.get(ConceptManager.CONCEPTS_BY_KEY_ENTRY, metadata.key) == metadata
|
|
assert om.get(ConceptManager.CONCEPTS_BY_HASH_ENTRY, metadata.digest) == metadata
|
|
|
|
# check first token
|
|
assert om.get(ConceptManager.CONCEPT_BY_FIRST_TOKEN_IN_KEY, "multiplied") == ["1001"]
|
|
|
|
def test_i_can_define_a_new_concept_using_definition(self, context, service):
|
|
with NewOntology(context, "test_i_can_define_a_new_concept_using_definition"):
|
|
res = service.define_new_concept(context,
|
|
name="multiplication",
|
|
definition="a multiplied by b",
|
|
variables=[("a", NotInit), ("b", NotInit)])
|
|
|
|
metadata = res.value.metadata
|
|
assert isinstance(metadata, ConceptMetadata)
|
|
assert metadata.id == "1001"
|
|
assert metadata.name == "multiplication"
|
|
assert metadata.definition == "a multiplied by b"
|
|
assert metadata.key == "__var__0 multiplied by __var__1"
|
|
assert metadata.digest == "b29007ea67bddc48329a2ae0124a320e26c86fb6b106aad6581bc75dfdf5ebeb"
|
|
assert metadata.all_attrs == ('#where#', '#pre#', '#post#', '#body#', '#ret#', "a", "b")
|
|
|
|
# is sorted in db
|
|
om = context.sheerka.om
|
|
assert om.get(ConceptManager.CONCEPTS_BY_ID_ENTRY, metadata.id) == metadata
|
|
assert om.get(ConceptManager.CONCEPTS_BY_NAME_ENTRY, metadata.name) == metadata
|
|
assert om.get(ConceptManager.CONCEPTS_BY_KEY_ENTRY, metadata.key) == metadata
|
|
assert om.get(ConceptManager.CONCEPTS_BY_HASH_ENTRY, metadata.digest) == metadata
|
|
|
|
# check first token
|
|
assert om.get(ConceptManager.CONCEPT_BY_FIRST_TOKEN_IN_KEY, "multiplied") == ["1001"]
|
|
assert om.get(ConceptManager.CONCEPT_BY_FIRST_TOKEN_IN_NAME, "multiplication") == ["1001"]
|
|
|
|
def test_i_cannot_create_the_same_concept_twice(self, context, service):
|
|
with NewOntology(context, "test_i_cannot_create_the_same_concept_twice"):
|
|
res = service.define_new_concept(context, "name", body="body")
|
|
assert res.status
|
|
|
|
res = service.define_new_concept(context, "name", body="body")
|
|
assert not res.status
|
|
assert isinstance(res.value, ErrorContext)
|
|
assert isinstance(res.value.value, ConceptAlreadyDefined)
|
|
|
|
def test_i_can_add_the_same_concept_on_different_ontologies(self, context, service):
|
|
with NewOntology(context, "test_i_can_add_the_same_concept_on_different_ontologies"):
|
|
res = service.define_new_concept(context, "name", body="body")
|
|
assert res.status
|
|
|
|
sheerka = context.sheerka
|
|
om = sheerka.om
|
|
om.push_ontology("my_new_ontology")
|
|
res = service.define_new_concept(context, "name", body="body")
|
|
assert res.status is True
|
|
|
|
def test_i_cannot_get_by_if_concept_does_not_exist(self, service):
|
|
assert service.get_by_id("unresolved_id") == NotFound
|
|
assert service.get_by_name("unresolved name") == NotFound
|
|
assert service.get_by_key("unresolved_hash") == NotFound
|
|
|
|
def test_i_can_get_a_newly_created_concept(self, context, service):
|
|
with NewOntology(context, "test_i_can_get_a_newly_created_concept"):
|
|
res = service.define_new_concept(context, "name", body="body")
|
|
assert res.status
|
|
metadata = res.value.metadata
|
|
|
|
assert service.get_by_id(metadata.id).id == metadata.id
|
|
assert service.get_by_name(metadata.name).name == metadata.name
|
|
assert service.get_by_key(metadata.key).key == metadata.key
|
|
|
|
def test_i_can_instantiate_a_new_concept_by_its_name(self, context, service):
|
|
with NewOntology(context, "test_i_can_instantiate_a_new_concept_by_its_name"):
|
|
res = service.define_new_concept(context, "foo", variables=[("var1", None), ("var2", None)])
|
|
assert res.status
|
|
|
|
foo = service.newn("foo", var1="value1", var2="value2")
|
|
|
|
assert foo.id == "1001"
|
|
assert foo.key == "foo"
|
|
assert foo.name == "foo"
|
|
assert foo.str_id == "c:#1001:"
|
|
assert foo.var1 == "value1"
|
|
assert foo.var2 == "value2"
|
|
|
|
def test_i_can_manage_when_concepts_with_the_same_name(self, context, service):
|
|
with NewOntology(context, "test_i_can_manage_when_concepts_with_the_same_name"):
|
|
service.define_new_concept(context, "foo", body="body1")
|
|
service.define_new_concept(context, "foo", body="body2")
|
|
|
|
concepts = service.newn("foo")
|
|
|
|
assert len(concepts) == 2
|
|
assert concepts[0].name == "foo"
|
|
assert concepts[0].get_metadata().body == "body1"
|
|
assert concepts[1].name == "foo"
|
|
assert concepts[1].get_metadata().body == "body2"
|
|
|
|
def test_i_can_instantiate_a_new_concept_by_its_id(self, context, service):
|
|
with NewOntology(context, "test_i_can_instantiate_a_new_concept_by_its_id"):
|
|
res = service.define_new_concept(context, "foo", variables=[("var1", None), ("var2", None)])
|
|
assert res.status
|
|
|
|
foo = service.newi("1001", var1="value1", var2="value2")
|
|
|
|
assert foo.id == "1001"
|
|
assert foo.key == "foo"
|
|
assert foo.name == "foo"
|
|
assert foo.str_id == "c:#1001:"
|
|
assert foo.var1 == "value1"
|
|
assert foo.var2 == "value2"
|
|
|
|
def test_i_cannot_instantiate_a_concept_which_does_not_exist(self, context, service):
|
|
foo = service.newn("foo", var1="value1", var2="value2")
|
|
assert foo.key == BuiltinConcepts.UNKNOWN_CONCEPT
|
|
assert foo.requested == "foo"
|
|
|
|
foo = service.newi("1001", var1="value1", var2="value2")
|
|
assert foo.key == BuiltinConcepts.UNKNOWN_CONCEPT
|
|
assert foo.requested == "#1001"
|
|
|
|
def test_i_can_instantiate_by_name_when_multiple_results(self, context, service):
|
|
with NewOntology(context, "test_i_can_instantiate_by_name_when_multiple_results"):
|
|
service.define_new_concept(context, "foo", body="body1")
|
|
service.define_new_concept(context, "foo", body="body2")
|
|
|
|
concepts = service.newn("foo")
|
|
|
|
assert len(concepts) == 2
|
|
assert concepts[0].id == "1001"
|
|
assert concepts[0].get_metadata().body == "body1"
|
|
assert concepts[1].id == "1002"
|
|
assert concepts[1].get_metadata().body == "body2"
|
|
|
|
def test_concepts_are_removed_when_ontology_is_popped(self, context, service):
|
|
context.sheerka.om.push_ontology("new ontology")
|
|
res = service.define_new_concept(context, "foo", body="body")
|
|
assert service.get_by_id(res.value.metadata.id) is not NotFound
|
|
|
|
context.sheerka.om.pop_ontology(context)
|
|
assert service.get_by_id(res.value.metadata.id) is NotFound
|
|
|
|
def test_i_can_new(self, context, service):
|
|
with NewOntology(context, "test_i_can_new"):
|
|
res = service.define_new_concept(context, "name", body="body", variables=[("my_var", None)])
|
|
assert res.status
|
|
metadata = res.value.metadata
|
|
|
|
# I can create a new concept
|
|
res = service.new(metadata, my_var="my_var_value")
|
|
assert res.id == metadata.id
|
|
assert res.my_var == "my_var_value"
|
|
|
|
res = service.new((metadata.name, None), my_var="my_var_value")
|
|
assert res.id == metadata.id
|
|
assert res.my_var == "my_var_value"
|
|
|
|
res = service.new((None, metadata.id), my_var="my_var_value")
|
|
assert res.id == metadata.id
|
|
assert res.my_var == "my_var_value"
|
|
|
|
res = service.new("c:name:", my_var="my_var_value")
|
|
assert res.id == metadata.id
|
|
assert res.my_var == "my_var_value"
|
|
|
|
res = service.new("c:#1001:", my_var="my_var_value")
|
|
assert res.id == metadata.id
|
|
assert res.my_var == "my_var_value"
|
|
|
|
res = service.new("c:name#1001:", my_var="my_var_value")
|
|
assert res.id == metadata.id
|
|
assert res.my_var == "my_var_value"
|
|
|
|
# cannot new using id
|
|
assert service.new(f"1001").name == BuiltinConcepts.UNKNOWN_CONCEPT
|
|
|
|
def test_id_is_used_when_name_and_id_are_provided(self, context, service):
|
|
with NewOntology(context, "test_id_is_used_when_name_and_id_are_provided"):
|
|
res = service.define_new_concept(context, "name", body="body1")
|
|
metadata = res.value.metadata
|
|
service.define_new_concept(context, "name", body="body2")
|
|
|
|
assert service.new((metadata.name, metadata.id)).id == metadata.id
|
|
|
|
def test_i_can_instantiate_a_list_of_concepts(self, context, service):
|
|
with NewOntology(context, "test_i_can_instantiate_a_list_of_concepts"):
|
|
foo, bar = get_concepts(context, "foo", "bar", use_sheerka=True)
|
|
|
|
res = service.new([foo.get_metadata(), bar.get_metadata()])
|
|
|
|
assert len(res) == 2
|
|
assert context.sheerka.isinstance(res[0], foo)
|
|
assert context.sheerka.isinstance(res[1], bar)
|
|
|
|
def test_i_can_new_using_concept_reference(self, context, service):
|
|
with NewOntology(context, "test_i_can_new_using_concept_reference"):
|
|
foo, bar, baz = get_concepts(context, "foo", "bar", "baz", use_sheerka=True)
|
|
|
|
foo.get_runtime_info().info["resolution_method"] = "id"
|
|
bar.get_runtime_info().info["resolution_method"] = "key"
|
|
|
|
foo_concept_ref = ConceptRef(foo)
|
|
res = service.new(foo_concept_ref)
|
|
assert context.sheerka.isinstance(res, foo)
|
|
|
|
bar_concept_ref = ConceptRef(bar)
|
|
res = service.new(bar_concept_ref)
|
|
assert context.sheerka.isinstance(res, bar)
|
|
|
|
baz_concept_ref = ConceptRef(baz)
|
|
res = service.new(baz_concept_ref)
|
|
assert context.sheerka.isinstance(res, baz)
|
|
|
|
def test_i_can_new_using_concept_reference_when_multiple_results(self, context, service):
|
|
with NewOntology(context, "test_i_can_new_using_concept_reference"):
|
|
foo1, foo2 = get_concepts(context,
|
|
get_concept("foo", body="1"),
|
|
get_concept("foo", body="2"),
|
|
use_sheerka=True)
|
|
|
|
foo = get_concept("foo") # blueprint, no need to be known by Sheerka
|
|
foo.get_runtime_info().info["resolution_method"] = "name"
|
|
foo_concept_ref = ConceptRef(foo)
|
|
|
|
res = service.new(foo_concept_ref)
|
|
assert res == [foo1, foo2]
|
|
|
|
def test_i_cannot_new_using_concept_reference_when_unknown(self, context, service):
|
|
foo = get_concept("foo") # not known by Sheerka
|
|
foo.get_runtime_info().info["resolution_method"] = "name"
|
|
|
|
foo_concept_ref = ConceptRef(foo)
|
|
res = service.new(foo_concept_ref)
|
|
assert context.sheerka.isinstance(res, BuiltinConcepts.UNKNOWN_CONCEPT)
|
|
assert res.requested == "foo"
|
|
|
|
def test_unknown_concept_is_return_if_the_identifier_is_not_found(self, service):
|
|
assert service.new("unknown").name == BuiltinConcepts.UNKNOWN_CONCEPT
|
|
|
|
def test_can_get_all_concepts(self, context, service):
|
|
with NewOntology(context, "test_i_can_new"):
|
|
service.define_new_concept(context, "foo")
|
|
service.define_new_concept(context, "bar")
|
|
context.sheerka.om.push_ontology("another ontology")
|
|
service.define_new_concept(context, "baz")
|
|
service.define_new_concept(context, "qux")
|
|
|
|
all_concepts = service.get_all_concepts()
|
|
assert [c.name for c in all_concepts if not c.is_builtin] == ["foo", "bar", "baz", "qux"]
|
|
|
|
# sanity check. Concepts are discarded when ontology is popped
|
|
context.sheerka.om.pop_ontology(context)
|
|
all_concepts = service.get_all_concepts()
|
|
assert [c.name for c in all_concepts if not c.is_builtin] == ["foo", "bar"]
|