1250 lines
46 KiB
Python
1250 lines
46 KiB
Python
import pytest
|
|
from core.builtin_concepts import BuiltinConcepts
|
|
from core.concept import Concept, PROPERTIES_TO_SERIALIZE, simplec, CMV, NotInit, CC
|
|
from evaluators.MutipleSameSuccessEvaluator import MultipleSameSuccessEvaluator
|
|
from evaluators.OneSuccessEvaluator import OneSuccessEvaluator
|
|
from evaluators.PythonEvaluator import PythonEvalError
|
|
from parsers.BaseNodeParser import SyaAssociativity
|
|
from parsers.BnfNodeParser import Sequence, StrMatch, OrderedChoice, Optional, ConceptExpression
|
|
|
|
from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka
|
|
from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka
|
|
|
|
|
|
class TestSheerkaNonRegMemory(TestUsingMemoryBasedSheerka):
|
|
|
|
@pytest.mark.parametrize("text, expected", [
|
|
("1 + 1", 2),
|
|
("sheerka.test()", 'I have access to Sheerka !')
|
|
])
|
|
def test_i_can_evaluate_python_expressions_with_no_variable(self, text, expected):
|
|
sheerka = self.get_sheerka()
|
|
|
|
res = sheerka.evaluate_user_input(text)
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].value == expected
|
|
|
|
def test_i_can_recognize_concept_with_python_body(self):
|
|
sheerka = self.get_sheerka()
|
|
concept = Concept(name="one", body="1")
|
|
sheerka.add_in_cache(concept)
|
|
|
|
text = "one"
|
|
res = sheerka.evaluate_user_input(text)
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].value == concept
|
|
|
|
# sanity check
|
|
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value)
|
|
assert evaluated == simplec("one", 1)
|
|
|
|
def test_i_can_recognize_concept_with_concept_body(self):
|
|
sheerka = self.get_sheerka()
|
|
concept_one = Concept(name="one")
|
|
concept_un = Concept(name="un", body="one")
|
|
sheerka.add_in_cache(concept_one)
|
|
sheerka.add_in_cache(concept_un)
|
|
|
|
res = sheerka.evaluate_user_input("un")
|
|
return_value = res[0].value
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert return_value == concept_un
|
|
|
|
# sanity check
|
|
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), return_value)
|
|
assert evaluated == simplec("un", simplec("one", BuiltinConcepts.NOT_INITIALIZED))
|
|
|
|
def test_i_can_recognize_concept_with_no_body(self):
|
|
sheerka = self.get_sheerka()
|
|
concept = Concept(name="one")
|
|
sheerka.add_in_cache(concept)
|
|
|
|
text = "one"
|
|
res = sheerka.evaluate_user_input(text)
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].value == concept
|
|
assert id(res[0].value) != id(concept)
|
|
|
|
def test_is_unique_property_is_used_when_evaluating(self):
|
|
sheerka = self.get_sheerka()
|
|
concept = Concept(name="one", is_unique=True)
|
|
sheerka.add_in_cache(concept)
|
|
|
|
text = "one"
|
|
res = sheerka.evaluate_user_input(text)
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].value == concept
|
|
assert id(res[0].value) == id(concept)
|
|
|
|
def test_i_can_evaluate_def_concept_request(self):
|
|
text = """
|
|
def concept a + b
|
|
where isinstance(a, int) and isinstance(b, int)
|
|
pre isinstance(a, int) and isinstance(b, int)
|
|
post isinstance(res, int)
|
|
as:
|
|
def func(x,y):
|
|
return x+y
|
|
func(a,b)
|
|
"""
|
|
|
|
expected = self.get_default_concept()
|
|
expected.metadata.id = "1001"
|
|
expected.metadata.desc = None
|
|
expected.metadata.variables = [("a", None), ("b", None)]
|
|
expected.init_key()
|
|
|
|
sheerka = self.get_sheerka(cache_only=False)
|
|
res = sheerka.evaluate_user_input(text)
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
|
|
|
|
concept_saved = res[0].value.body
|
|
|
|
for prop in PROPERTIES_TO_SERIALIZE:
|
|
assert getattr(concept_saved.metadata, prop) == getattr(expected.metadata, prop)
|
|
|
|
# cache is up to date
|
|
assert sheerka.has_key(concept_saved.key)
|
|
assert sheerka.has_id(concept_saved.id)
|
|
assert sheerka.has_name(concept_saved.name)
|
|
assert sheerka.has_hash(concept_saved.get_definition_hash())
|
|
assert sheerka.cache_manager.copy(sheerka.CONCEPTS_BY_FIRST_KEYWORD_ENTRY) == {'+': ['1001']}
|
|
|
|
# sdp is up to date
|
|
assert sheerka.sdp.exists(sheerka.CONCEPTS_BY_KEY_ENTRY, expected.key)
|
|
|
|
def test_i_can_evaluate_def_concept_part_when_one_part_is_a_ref_of_another_concept(self):
|
|
"""
|
|
In this test, we test that the properties of 'concept a xx b' (which are 'a' and 'b')
|
|
are correctly detected, thanks to the source code 'a plus b' in its body
|
|
:return:
|
|
"""
|
|
sheerka = self.get_sheerka()
|
|
|
|
# concept 'a plus b' is known
|
|
concept_a_plus_b = Concept(name="a plus b").def_var("a").def_var("b").init_key()
|
|
sheerka.add_in_cache(concept_a_plus_b)
|
|
|
|
res = sheerka.evaluate_user_input("def concept a xx b as a plus b")
|
|
expected = Concept(name="a xx b", body="a plus b").def_var("a").def_var("b").init_key()
|
|
expected.metadata.id = "1001"
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
|
|
|
|
concept_saved = res[0].value.body
|
|
|
|
for prop in PROPERTIES_TO_SERIALIZE:
|
|
assert getattr(concept_saved.metadata, prop) == getattr(expected.metadata, prop)
|
|
|
|
assert sheerka.has_key(concept_saved.key)
|
|
|
|
def test_i_cannot_evaluate_the_same_def_concept_twice(self):
|
|
text = """
|
|
def concept a + b
|
|
where isinstance(a, int) and isinstance(b, int)
|
|
pre isinstance(a, int) and isinstance(b, int)
|
|
post isinstance(res, int)
|
|
as:
|
|
def func(x,y):
|
|
return x+y
|
|
func(a,b)
|
|
"""
|
|
|
|
sheerka = self.get_sheerka()
|
|
sheerka.evaluate_user_input(text)
|
|
res = sheerka.evaluate_user_input(text)
|
|
|
|
assert len(res) == 1
|
|
assert not res[0].status
|
|
assert sheerka.isinstance(res[0].value, BuiltinConcepts.ALREADY_DEFINED)
|
|
|
|
@pytest.mark.parametrize("text", [
|
|
"",
|
|
" ",
|
|
"\n",
|
|
])
|
|
def test_i_can_recognize_a_empty_input(self, text):
|
|
sheerka = self.get_sheerka()
|
|
|
|
res = sheerka.evaluate_user_input(text)
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NOP)
|
|
|
|
def test_i_can_recognize_concept_with_variable(self):
|
|
sheerka, context, concept_foo, concept_hello = self.init_concepts(
|
|
"foo",
|
|
Concept(name="hello a").def_var("a"),
|
|
create_new=True)
|
|
|
|
res = sheerka.evaluate_user_input("hello foo")
|
|
return_value = res[0].value
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(return_value, concept_hello)
|
|
|
|
# sanity check
|
|
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), return_value)
|
|
assert evaluated.get_value("a") == concept_foo
|
|
|
|
def test_i_can_recognize_concept_with_variable_and_python_as_body(self):
|
|
sheerka = self.get_sheerka()
|
|
hello_a = sheerka.add_in_cache(Concept(name="hello a", body="'hello ' + a").def_var("a"))
|
|
sheerka.add_in_cache(Concept(name="foo", body="'foo'"))
|
|
|
|
res = sheerka.evaluate_user_input("hello foo")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].value, hello_a)
|
|
|
|
# sanity check
|
|
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value)
|
|
assert evaluated.body == "hello foo"
|
|
assert evaluated.metadata.is_evaluated
|
|
assert evaluated.get_value("a") == simplec("foo", "foo")
|
|
assert evaluated.get_value("a").metadata.is_evaluated
|
|
|
|
def test_i_can_recognize_duplicate_concepts_with_same_value(self):
|
|
# when multiple result, choose the one that is the more specific (that has the less variables)
|
|
sheerka = self.get_sheerka()
|
|
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello a", body="'hello ' + a"), variables=["a"])
|
|
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello foo", body="'hello foo'"))
|
|
self.create_and_add_in_cache_concept(sheerka, Concept(name="foo", body="'foo'"))
|
|
|
|
res = sheerka.evaluate_user_input("hello foo")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].body, "hello foo")
|
|
assert res[0].value.body == BuiltinConcepts.NOT_INITIALIZED
|
|
assert res[0].who == sheerka.get_evaluator_name(OneSuccessEvaluator.NAME)
|
|
|
|
def test_i_cannot_manage_duplicate_concepts_when_the_values_are_different(self):
|
|
sheerka = self.get_sheerka()
|
|
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello a", body="'hello ' + a").def_var("a"))
|
|
self.create_and_add_in_cache_concept(sheerka, Concept(name="hello b", body="'hello you ' + b").def_var("b"))
|
|
self.create_and_add_in_cache_concept(sheerka, Concept(name="foo", body="'another value'"))
|
|
|
|
res = sheerka.evaluate_user_input("eval hello foo")
|
|
assert len(res) == 1
|
|
assert not res[0].status
|
|
assert sheerka.isinstance(res[0].value, BuiltinConcepts.TOO_MANY_SUCCESS)
|
|
|
|
concepts = res[0].value.body
|
|
assert len(concepts) == 2
|
|
sorted_values = sorted(concepts, key=lambda x: x.value)
|
|
assert sorted_values[0].value == "hello another value"
|
|
assert sorted_values[1].value == "hello you another value"
|
|
|
|
def test_i_can_manage_concepts_with_the_same_key_when_values_are_the_same(self):
|
|
sheerka = self.get_sheerka()
|
|
context = self.get_context(sheerka)
|
|
|
|
sheerka.create_new_concept(context, Concept(name="hello a", body="'hello ' + a").def_var("a"))
|
|
sheerka.create_new_concept(context, Concept(name="hello b", body="'hello ' + b").def_var("b"))
|
|
|
|
res = sheerka.evaluate_user_input("eval hello 'foo'")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].value == "hello foo" # I don't know yet the one to choose
|
|
assert res[0].who == sheerka.get_evaluator_name(MultipleSameSuccessEvaluator.NAME)
|
|
|
|
def test_i_can_create_concepts_with_python_code_as_body(self):
|
|
sheerka = self.get_sheerka()
|
|
context = self.get_context(sheerka)
|
|
|
|
sheerka.create_new_concept(context, Concept(name="concepts", body="sheerka.test()"))
|
|
res = sheerka.evaluate_user_input("eval concepts")
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].value == sheerka.test()
|
|
|
|
def test_i_can_recognize_bnf_definitions(self):
|
|
sheerka = self.get_sheerka()
|
|
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body
|
|
|
|
res = sheerka.evaluate_user_input("one")
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].value, concept_a)
|
|
|
|
def test_i_can_recognize_bnf_definitions_with_variables(self):
|
|
sheerka = self.get_sheerka()
|
|
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' | 'two'")[0].body.body
|
|
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
|
|
|
|
res = sheerka.evaluate_user_input("one three")
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
return_value = res[0].value
|
|
|
|
assert sheerka.isinstance(return_value, concept_b)
|
|
|
|
# sanity check
|
|
evaluated = sheerka.evaluate_concept(self.get_context(sheerka=sheerka, eval_body=True), return_value)
|
|
assert evaluated.body == "one three"
|
|
assert evaluated.metadata.is_evaluated
|
|
assert evaluated.get_value("a") == sheerka.new(concept_a.key, body="one").init_key()
|
|
assert evaluated.get_value("a").metadata.is_evaluated
|
|
|
|
@pytest.mark.parametrize("user_input", [
|
|
"def concept greetings from def hello a where a",
|
|
"def concept greetings from hello a where a"])
|
|
def test_i_can_recognize_a_concept_defined_using_from_def(self, user_input):
|
|
sheerka = self.get_sheerka()
|
|
|
|
greetings = sheerka.evaluate_user_input(user_input)[0].body.body
|
|
|
|
res = sheerka.evaluate_user_input("hello 'foo'")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
concept_found = res[0].value
|
|
assert sheerka.isinstance(concept_found, greetings)
|
|
assert concept_found.get_value("a") == "foo"
|
|
assert concept_found.metadata.need_validation
|
|
|
|
res = sheerka.evaluate_user_input("greetings")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
concept_found = res[0].value
|
|
assert sheerka.isinstance(concept_found, greetings)
|
|
assert concept_found.get_value("a") == NotInit
|
|
assert not concept_found.metadata.need_validation
|
|
|
|
@pytest.mark.parametrize("desc, definitions", [
|
|
("Simple form", [
|
|
"def concept one as 1",
|
|
"def concept two as 2",
|
|
"def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit"
|
|
]),
|
|
("When twenty is a concept", [
|
|
"def concept one as 1",
|
|
"def concept two as 2",
|
|
"def concept twenty as 20",
|
|
"def concept twenties from bnf twenty (one|two)=unit as twenty + unit"
|
|
]),
|
|
("When digit is a concept", [
|
|
"def concept one as 1",
|
|
"def concept two as 2",
|
|
"def concept twenty as 20",
|
|
"def concept digit from bnf one|two",
|
|
"def concept twenties from bnf twenty digit as twenty + digit"
|
|
]),
|
|
("When using isa and concept twenty", [
|
|
"def concept one as 1",
|
|
"def concept two as 2",
|
|
"def concept number",
|
|
"set_isa(one, number)",
|
|
"set_isa(two, number)",
|
|
"def concept twenties from bnf 'twenty' number as 20 + number"
|
|
]),
|
|
("When using isa and concept twenty", [
|
|
"def concept one as 1",
|
|
"def concept two as 2",
|
|
"def concept twenty as 20",
|
|
"def concept number",
|
|
"set_isa(one, number)",
|
|
"set_isa(two, number)",
|
|
"def concept twenties from bnf twenty number as 20 + number"
|
|
]),
|
|
])
|
|
def test_i_can_mix_concept_with_python_to_define_numbers(self, desc, definitions):
|
|
sheerka = self.get_sheerka()
|
|
|
|
for definition in definitions:
|
|
sheerka.evaluate_user_input(definition)
|
|
|
|
res = sheerka.evaluate_user_input("twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].body, "twenties")
|
|
assert sheerka.evaluate_concept(self.get_context(sheerka=sheerka, eval_body=True), res[0].body).body == 21
|
|
|
|
res = sheerka.evaluate_user_input("twenty one + 1")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 22
|
|
|
|
res = sheerka.evaluate_user_input("twenty one + one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 22
|
|
|
|
res = sheerka.evaluate_user_input("twenty one + twenty two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 43
|
|
|
|
res = sheerka.evaluate_user_input("1 + twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 22
|
|
|
|
res = sheerka.evaluate_user_input("1 + 1 + twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 23
|
|
|
|
def test_i_can_mix_bnf_and_isa(self):
|
|
"""
|
|
if 'one' isa 'number, twenty number should be recognized
|
|
:return:
|
|
"""
|
|
sheerka = self.get_sheerka()
|
|
sheerka.evaluate_user_input("def concept one as 1")
|
|
sheerka.evaluate_user_input("def concept two as 2")
|
|
sheerka.evaluate_user_input("def concept number")
|
|
sheerka.evaluate_user_input("set_isa(one, number)")
|
|
sheerka.evaluate_user_input("set_isa(two, number)")
|
|
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' number as 20 + number")
|
|
|
|
res = sheerka.evaluate_user_input("twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].body, "twenties")
|
|
assert sheerka.evaluate_concept(self.get_context(sheerka=sheerka, eval_body=True), res[0].value).body == 21
|
|
|
|
res = sheerka.evaluate_user_input("twenty one + 1")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 22
|
|
|
|
res = sheerka.evaluate_user_input("twenty one + one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 22
|
|
|
|
res = sheerka.evaluate_user_input("twenty one + twenty two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 43
|
|
|
|
res = sheerka.evaluate_user_input("1 + twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 22
|
|
|
|
res = sheerka.evaluate_user_input("1 + 1 + twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 23
|
|
|
|
def test_i_can_mix_bnf_and_isa_2(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
init = [
|
|
"def concept one as 1",
|
|
"def concept twenty as 20",
|
|
"def concept number",
|
|
"set_isa(one, number)",
|
|
"set_isa(twenty, number)",
|
|
"def concept twenties from bnf twenty number as twenty + number"
|
|
]
|
|
|
|
for exp in init:
|
|
sheerka.evaluate_user_input(exp)
|
|
|
|
res = sheerka.evaluate_user_input("eval twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 21
|
|
|
|
def test_i_can_use_concepts_defined_with_from(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
init = [
|
|
"def concept plus from a plus b as a + b",
|
|
"def concept one as 1",
|
|
]
|
|
|
|
for exp in init:
|
|
sheerka.evaluate_user_input(exp)
|
|
|
|
res = sheerka.evaluate_user_input("eval one plus one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 2
|
|
|
|
res = sheerka.evaluate_user_input("eval 1 plus one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 2
|
|
|
|
res = sheerka.evaluate_user_input("eval one plus 1")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 2
|
|
|
|
res = sheerka.evaluate_user_input("eval 1 plus 2")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 3
|
|
|
|
res = sheerka.evaluate_user_input("eval 1 plus 1")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 2
|
|
|
|
def test_i_can_mix_bnf_concept_and_concept(self):
|
|
definitions = [
|
|
"def concept one as 1",
|
|
"def concept two as 2",
|
|
"def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit",
|
|
"def concept a plus b as a + b"
|
|
]
|
|
|
|
sheerka = self.init_scenario(definitions)
|
|
|
|
res = sheerka.evaluate_user_input("eval 1 plus 2")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 3
|
|
|
|
res = sheerka.evaluate_user_input("eval 1 plus one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 2
|
|
|
|
res = sheerka.evaluate_user_input("eval 1 + 1 plus 1")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 3
|
|
|
|
res = sheerka.evaluate_user_input("eval 1 plus twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 22
|
|
|
|
res = sheerka.evaluate_user_input("eval one plus 1")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 2
|
|
|
|
res = sheerka.evaluate_user_input("eval one plus two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 3
|
|
|
|
res = sheerka.evaluate_user_input("eval one plus twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 22
|
|
|
|
res = sheerka.evaluate_user_input("eval twenty one plus 1")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 22
|
|
|
|
res = sheerka.evaluate_user_input("eval twenty one plus one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 22
|
|
|
|
res = sheerka.evaluate_user_input("eval twenty one plus twenty two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 43
|
|
|
|
def test_i_can_use_bnf_alias(self):
|
|
definitions = [
|
|
"def concept two as 2",
|
|
"def concept number",
|
|
"set_isa(two, number)",
|
|
"def concept plus_one from bnf number=n1 'plus_one' as n1 + 1",
|
|
]
|
|
|
|
sheerka = self.init_scenario(definitions)
|
|
|
|
res = sheerka.evaluate_user_input("eval two plus_one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 3
|
|
|
|
def test_eval_does_not_break_valid_result(self):
|
|
sheerka = self.get_sheerka()
|
|
sheerka.evaluate_user_input("def concept one as 1")
|
|
sheerka.evaluate_user_input("def concept two as 2")
|
|
|
|
res = sheerka.evaluate_user_input("one + two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 3
|
|
|
|
res = sheerka.evaluate_user_input("eval one + two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 3
|
|
|
|
@pytest.mark.parametrize("text", [
|
|
"'hello",
|
|
'"foo" + "string',
|
|
"c::",
|
|
"c:foo\nbar:",
|
|
"c:foo",
|
|
"def concept 'name",
|
|
"def concept name from bnf 'name"
|
|
])
|
|
def test_i_can_manage_tokenizer_error(self, text):
|
|
sheerka = self.get_sheerka()
|
|
sheerka.add_in_cache(Concept("foo"))
|
|
|
|
res = sheerka.evaluate_user_input(text)
|
|
|
|
assert len(res) > 1
|
|
for r in [r for r in res if r.who.startswith("parsers.")]:
|
|
assert not r.status
|
|
|
|
def test_i_can_recognize_concept_from_string(self):
|
|
sheerka = self.get_sheerka()
|
|
sheerka.add_in_cache(Concept("one", body="1"))
|
|
|
|
res = sheerka.evaluate_user_input("'one'")
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == "one"
|
|
|
|
res = sheerka.evaluate_user_input("eval 'one'")
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == "one"
|
|
|
|
@pytest.mark.parametrize("expression", [
|
|
"def concept twenties from bnf 'twenty' (one | two)=unit as 20 + unit",
|
|
"def concept twenties from bnf 'twenty' (one | two)=unit as twenty + unit",
|
|
"def concept twenties from bnf twenty (one | two)=unit as 20 + unit",
|
|
"def concept twenties from bnf twenty (one | two)=unit as twenty + unit",
|
|
])
|
|
def test_i_can_evaluate_bnf_concepts(self, expression):
|
|
sheerka = self.get_sheerka()
|
|
|
|
sheerka.evaluate_user_input("def concept one as 1")
|
|
sheerka.evaluate_user_input("def concept two as 2")
|
|
sheerka.evaluate_user_input("def concept twenty as 20")
|
|
sheerka.evaluate_user_input(expression)
|
|
res = sheerka.evaluate_user_input("eval twenty one")
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 21
|
|
|
|
def test_i_can_use_where_in_bnf(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
init = [
|
|
"def concept one as 1",
|
|
"def concept two as 2",
|
|
"def concept three as 3",
|
|
"def concept twenty as 20",
|
|
"def concept number",
|
|
"set_isa(one, number)",
|
|
"set_isa(two, number)",
|
|
"set_isa(three, number)",
|
|
"def concept twenties from bnf twenty number where number <= 2 as twenty + number"
|
|
]
|
|
|
|
for exp in init:
|
|
sheerka.evaluate_user_input(exp)
|
|
|
|
res = sheerka.evaluate_user_input("twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].body, "twenties")
|
|
|
|
res = sheerka.evaluate_user_input("eval twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 21
|
|
|
|
res = sheerka.evaluate_user_input("twenty two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].body, "twenties")
|
|
|
|
res = sheerka.evaluate_user_input("eval twenty two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 22
|
|
|
|
res = sheerka.evaluate_user_input("twenty three")
|
|
assert len(res) == 1
|
|
assert not res[0].status
|
|
assert sheerka.isinstance(res[0].body, BuiltinConcepts.MULTIPLE_ERRORS)
|
|
assert str(BuiltinConcepts.CONDITION_FAILED) in [error.key for error in sheerka.get_error(res[0].body.body)]
|
|
|
|
res = sheerka.evaluate_user_input("eval twenty three")
|
|
assert len(res) == 1
|
|
assert not res[0].status
|
|
assert str(BuiltinConcepts.CONDITION_FAILED) in [error.key for error in sheerka.get_error(res[0].body.body)]
|
|
|
|
def test_i_can_manage_some_type_of_infinite_recursion(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
sheerka.evaluate_user_input("def concept one as 1")
|
|
sheerka.evaluate_user_input("def concept 1 as one")
|
|
res = sheerka.evaluate_user_input("one + 1")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 2
|
|
|
|
res = sheerka.evaluate_user_input("1 + 1")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 2
|
|
|
|
def test_i_can_evaluate_bnf_concept_with_where_clause(self):
|
|
sheerka = self.get_sheerka()
|
|
|
|
sheerka.evaluate_user_input("def concept a from bnf 'bar' | 'baz'")
|
|
sheerka.evaluate_user_input("def concept b as 'hello world'")
|
|
sheerka.evaluate_user_input("def concept foobar from bnf 'foo' a where a=='bar' as b")
|
|
|
|
res = sheerka.evaluate_user_input("foo bar")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].body, "foobar")
|
|
assert res[0].body.body == BuiltinConcepts.NOT_INITIALIZED
|
|
|
|
res = sheerka.evaluate_user_input("eval foo bar")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == "hello world"
|
|
|
|
res = sheerka.evaluate_user_input("foo baz")
|
|
assert len(res) == 1
|
|
assert not res[0].status
|
|
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
|
|
|
|
res = sheerka.evaluate_user_input("eval foo baz")
|
|
assert len(res) == 1
|
|
assert not res[0].status
|
|
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
|
|
|
|
res = sheerka.evaluate_user_input("foobar")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
|
|
res = sheerka.evaluate_user_input("eval foobar")
|
|
assert len(res) == 1 # error
|
|
assert not res[0].status
|
|
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
|
|
|
|
@pytest.mark.skip("Not ready for that")
|
|
def test_i_can_manage_missing_variables_from_bnf_parsing(self):
|
|
definitions = [
|
|
"def concept one as 1",
|
|
"def concept number",
|
|
"set_isa(one, number)",
|
|
"def concept hundreds from bnf number=n1 'hundred' ('and' number=n2)? where n1<10 and n2<100 as n1 * 100 + n2",
|
|
]
|
|
|
|
sheerka = self.init_scenario(definitions)
|
|
|
|
res = sheerka.evaluate_user_input("one hundred")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].body, "hundreds")
|
|
|
|
res = sheerka.evaluate_user_input("eval one hundred")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == "100"
|
|
|
|
def test_i_can_say_than_bnf_concept_isa_another_concept(self):
|
|
sheerka = self.get_sheerka()
|
|
sheerka.evaluate_user_input("def concept number")
|
|
sheerka.evaluate_user_input("def concept one as 1")
|
|
sheerka.evaluate_user_input("def concept two as 2")
|
|
sheerka.evaluate_user_input("def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit")
|
|
|
|
res = sheerka.evaluate_user_input("set_isa(twenties, number)")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
|
|
twenties = sheerka.get_by_key("twenties")
|
|
number = sheerka.get_by_key("number")
|
|
assert sheerka.isa(twenties, number)
|
|
|
|
def test_i_can_mix_sya_concepts_and_bnf_concept(self):
|
|
definitions = [
|
|
"def concept one as 1",
|
|
"def concept two as 2",
|
|
"def concept three as 3",
|
|
"def concept plus from a plus b as a + b",
|
|
"def concept mult from a mult b as a * b",
|
|
"def concept twenties from bnf 'twenty' (one|two)=unit as 20 + unit",
|
|
]
|
|
|
|
sheerka = self.init_scenario(definitions)
|
|
context = self.get_context(sheerka)
|
|
sheerka.force_sya_def(context, [
|
|
(sheerka.get_by_name("mult").id, 20, SyaAssociativity.Right),
|
|
(sheerka.get_by_name("plus").id, 10, SyaAssociativity.Right),
|
|
])
|
|
|
|
res = sheerka.evaluate_user_input("eval one plus two mult three")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 7
|
|
|
|
res = sheerka.evaluate_user_input("eval two mult three plus one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 7
|
|
|
|
res = sheerka.evaluate_user_input("eval 1 plus two mult 3")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 7
|
|
|
|
res = sheerka.evaluate_user_input("eval 2 mult 3 plus one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 7
|
|
|
|
res = sheerka.evaluate_user_input("eval twenty two plus 1")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 23
|
|
|
|
res = sheerka.evaluate_user_input("eval 1 plus twenty two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 23
|
|
|
|
res = sheerka.evaluate_user_input("eval twenty one plus twenty two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 43
|
|
|
|
res = sheerka.evaluate_user_input("eval twenty two plus twenty one mult two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 64
|
|
|
|
def test_concepts_parsed_by_atom_parser_must_not_be_evaluated(self):
|
|
definitions = [
|
|
"def concept mult from a mult b as a * b",
|
|
"def concept a mult b as a * b",
|
|
]
|
|
|
|
sheerka = self.init_scenario(definitions)
|
|
|
|
res = sheerka.evaluate_user_input("eval mult")
|
|
assert res[0].status
|
|
assert isinstance(res[0].body, Concept)
|
|
|
|
# res = sheerka.evaluate_user_input("eval a mult b")
|
|
# assert res[0].status
|
|
# assert isinstance(res[0].body, Concept)
|
|
|
|
def test_i_can_express_comparison(self):
|
|
definitions = [
|
|
"def concept one",
|
|
"def concept two",
|
|
"def concept three",
|
|
"def concept four",
|
|
]
|
|
|
|
sheerka = self.init_scenario(definitions)
|
|
|
|
res = sheerka.evaluate_user_input("set_is_greater_than('some_prop', two, one)")
|
|
assert res[0].status
|
|
|
|
res = sheerka.evaluate_user_input("set_is_less_than('some_prop', two, three)")
|
|
assert res[0].status
|
|
|
|
res = sheerka.evaluate_user_input("get_concepts_weights('some_prop')")
|
|
assert res[0].status
|
|
assert res[0].body == {'1001': 1, '1002': 2, '1003': 3}
|
|
|
|
# test i use a concept to define relation
|
|
sheerka.evaluate_user_input("def concept a > b as set_is_greater_than('some_prop', a, b)")
|
|
res = sheerka.evaluate_user_input("eval four > three")
|
|
assert res[0].status
|
|
|
|
assert sheerka.get_concepts_weights("some_prop") == {'1001': 1, '1002': 2, '1003': 3, '1004': 4}
|
|
|
|
def test_i_can_evaluate_expression_when_using_token_concept(self):
|
|
sheerka, context, one, two, three, is_less_than = self.init_concepts(
|
|
Concept("one", body="1"),
|
|
Concept("two", body="2"),
|
|
Concept("three", body="3"),
|
|
self.from_def_concept("<", "a < b", ["a", "b"], body="set_is_less_than('some_prop', a, b)")
|
|
)
|
|
|
|
expression = "c:one: < c:two:"
|
|
res = sheerka.evaluate_user_input(expression)
|
|
assert res[0].status
|
|
assert res[0].body == CMV(is_less_than, a="c:one:", b="c:two:")
|
|
assert res[0].body.a == NotInit # concept is not evaluated
|
|
assert res[0].body.b == NotInit # concept is not evaluated
|
|
|
|
expression = "eval c:one: < c:two:"
|
|
res = sheerka.evaluate_user_input(expression)
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS)
|
|
assert sheerka.get_concepts_weights("some_prop") == {'1001': 1, '1002': 2}
|
|
|
|
# it now also works using the concepts names
|
|
expression = "eval two < three"
|
|
res = sheerka.evaluate_user_input(expression)
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].body, BuiltinConcepts.SUCCESS)
|
|
assert sheerka.get_concepts_weights("some_prop") == {'1001': 1, '1002': 2, '1003': 3}
|
|
|
|
def test_i_can_detect_multiple_errors_when_evaluating_a_concept(self):
|
|
sheerka, context, foo, plus_one = self.init_concepts(
|
|
Concept("foo", body="'string'"),
|
|
Concept("a plus one", body="a + 1").def_var("a")
|
|
)
|
|
|
|
res = sheerka.evaluate_user_input("eval foo plus one")
|
|
|
|
assert not res[0].status
|
|
assert context.sheerka.isinstance(res[0].body, BuiltinConcepts.CONCEPT_EVAL_ERROR)
|
|
assert context.sheerka.isinstance(res[0].body.body, BuiltinConcepts.TOO_MANY_ERRORS)
|
|
|
|
error0 = res[0].body.body.body[0]
|
|
assert isinstance(error0, PythonEvalError)
|
|
assert isinstance(error0.error, TypeError)
|
|
assert error0.error.args[0] == "unsupported operand type(s) for +: 'Concept' and 'int'"
|
|
|
|
error1 = res[0].body.body.body[1]
|
|
assert isinstance(error1, PythonEvalError)
|
|
assert isinstance(error1.error, TypeError)
|
|
assert error1.error.args[0] == 'can only concatenate str (not "int") to str'
|
|
|
|
def test_i_can_evaluate_bnf_concept_defined_with_group_after_restart(self):
|
|
"""
|
|
BNF Concepts defined with group and being themselves part a s group get messed up after restart
|
|
:return:
|
|
"""
|
|
init = [
|
|
"def concept one as 1",
|
|
"def concept two as 2",
|
|
"def concept twenty as 20",
|
|
"def concept number",
|
|
"set_isa(one, number)",
|
|
"set_isa(two, number)",
|
|
"set_isa(twenty, number)",
|
|
"def concept twenties from bnf twenty number where number < 10 as twenty + number",
|
|
"set_isa(twenties, number)",
|
|
]
|
|
|
|
sheerka = self.init_scenario(init)
|
|
|
|
# simulate that sheerka was stopped and restarted
|
|
sheerka.cache_manager.clear(sheerka.CONCEPTS_GRAMMARS_ENTRY)
|
|
sheerka.cache_manager.get(sheerka.CONCEPTS_BY_KEY_ENTRY, "twenties").compiled = {}
|
|
|
|
res = sheerka.evaluate_user_input("eval twenty one")
|
|
assert res[0].status
|
|
assert res[0].body == 21
|
|
|
|
def test_i_can_use_last_created_concept_to_define_set(self):
|
|
init = [
|
|
"def concept number",
|
|
"def concept one",
|
|
]
|
|
|
|
sheerka = self.init_scenario(init)
|
|
|
|
res = sheerka.evaluate_user_input("set_isa(last_created_concept(), number)")
|
|
|
|
assert res[0].status
|
|
assert sheerka.isa(sheerka.new("one"), sheerka.new("number"))
|
|
|
|
def test_i_can_evaluate_sya_and_ret_concepts(self):
|
|
init = [
|
|
"def concept one as 1",
|
|
"def concept plus from a plus b as a + b",
|
|
"def concept the a ret a"
|
|
]
|
|
|
|
sheerka = self.init_scenario(init)
|
|
the = sheerka.get_by_name("the a")
|
|
|
|
res = sheerka.evaluate_user_input("one plus the one")
|
|
assert res[0].status
|
|
plus = res[0].body
|
|
assert isinstance(plus, Concept)
|
|
assert plus.name == "plus"
|
|
assert plus.compiled["a"] == sheerka.new("one")
|
|
assert plus.compiled["b"] == CC(the, a=sheerka.new("one"))
|
|
|
|
res = sheerka.evaluate_user_input("eval one plus the one")
|
|
assert res[0].status
|
|
assert res[0].body == 2
|
|
|
|
def test_i_can_evaluate_command(self):
|
|
init = [
|
|
"def concept command as 'Executed !'",
|
|
"set_isa(c:command:, __AUTO_EVAL)",
|
|
]
|
|
|
|
# Since command is a __COMMAND, the body is auto evaluated
|
|
# and we return the body, not the concept
|
|
|
|
sheerka = self.init_scenario(init)
|
|
res = sheerka.evaluate_user_input("command")
|
|
assert res[0].status
|
|
assert res[0].body == "Executed !"
|
|
|
|
def test_i_can_manage_question(self):
|
|
init = [
|
|
"def concept one",
|
|
"def concept foo",
|
|
"def concept number",
|
|
"set_isa(one, number)",
|
|
"def concept x is a y as isa(x,y) pre in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)",
|
|
"def concept x is a y as set_isa(x,y)",
|
|
]
|
|
|
|
sheerka = self.init_scenario(init)
|
|
res = sheerka.evaluate_user_input("question(one is a number)") # automatically evaluated
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body
|
|
|
|
res = sheerka.evaluate_user_input("question(foo is a number)") # automatically evaluated
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert not res[0].body
|
|
|
|
def test_where_clause_implicitly_infer_to_question(self):
|
|
init = [
|
|
"def concept one as 1",
|
|
"def concept number",
|
|
"set_isa(one, number)",
|
|
"def concept one as 10", # to make sure that it won't be rejected because of the cast
|
|
"def concept x is a y as isa(x,y) pre in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)",
|
|
"def concept x is a y as set_isa(x,y)",
|
|
]
|
|
|
|
# Explanations
|
|
# There are two concepts 'one'. The first one is tagged as a number while the second one is not
|
|
# So the first one should be picked.
|
|
# the second concept 'one' 's value is an integer, to make sure that it won't be rejected because of its type
|
|
|
|
sheerka = self.init_scenario(init)
|
|
res = sheerka.evaluate_user_input("def concept x plus y where x is a number as x + y")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].body, BuiltinConcepts.NEW_CONCEPT)
|
|
|
|
# Let's check that the concept is correctly understood
|
|
res = sheerka.evaluate_user_input("eval one plus 2")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 3 # it means that the first 'one' was chosen
|
|
|
|
def test_i_can_manage_concept_that_refers_to_question(self):
|
|
init = [
|
|
"def concept one",
|
|
"def concept foo",
|
|
"def concept number",
|
|
"set_isa(one, number)",
|
|
"def concept q from q ? as question(q)",
|
|
"set_auto_eval(q)",
|
|
"def concept is_a from x is a y as isa(x,y) pre in_context(BuiltinConcepts.EVAL_QUESTION_REQUESTED)",
|
|
"set_is_greater_than(BuiltinConcepts.PRECEDENCE, c:is_a:, c:q:)",
|
|
]
|
|
|
|
sheerka = self.init_scenario(init)
|
|
res = sheerka.evaluate_user_input("one is a number ?") # automatically evaluated
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == True # the body MUST be a boolean
|
|
|
|
res = sheerka.evaluate_user_input("foo is a number ?") # automatically evaluated
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == False # the body MUST be a boolean
|
|
|
|
# x is a y is supposed to be a question. It cannot be used if not in a context of a question
|
|
res = sheerka.evaluate_user_input("one is a number")
|
|
assert len(res) == 1
|
|
assert not res[0].status
|
|
assert sheerka.isinstance(res[0].body, BuiltinConcepts.CONDITION_FAILED)
|
|
|
|
def test_i_can_evaluate_source_code_with_concept(self):
|
|
init = [
|
|
"def concept the a ret a",
|
|
]
|
|
|
|
sheerka = self.init_scenario(init)
|
|
res = sheerka.evaluate_user_input("desc(the a)")
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
|
|
def test_i_can_parse_concept_with_variables_using_short_name(self):
|
|
init = [
|
|
"def concept foo from a foo b where a,b",
|
|
"def concept bar from bar a where a",
|
|
"def concept baz from a baz where a",
|
|
]
|
|
|
|
sheerka = self.init_scenario(init)
|
|
res = sheerka.evaluate_user_input("desc(foo)")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
|
|
sheerka = self.init_scenario(init)
|
|
res = sheerka.evaluate_user_input("desc(bar)")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
|
|
sheerka = self.init_scenario(init)
|
|
res = sheerka.evaluate_user_input("desc(baz)")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
|
|
def test_i_can_eval_concepts_fed_with_functions(self):
|
|
init = [
|
|
"def concept inc a as a + 1",
|
|
"def concept one as 1"
|
|
]
|
|
|
|
def times_five(i):
|
|
return i * 5
|
|
|
|
sheerka = self.init_scenario(init)
|
|
sheerka.locals["times_five"] = times_five
|
|
|
|
res = sheerka.evaluate_user_input("eval inc times_five(one)")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body == 6
|
|
|
|
def test_i_can_define_a_concept_when_where_clause_contains_the_name_of_the_variable(self):
|
|
init = [
|
|
"def concept x is a y as isa(x,y) pre is_question()",
|
|
]
|
|
sheerka = self.init_scenario(init)
|
|
|
|
res = sheerka.evaluate_user_input("def concept a x b where a is a number as a + b")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].body, BuiltinConcepts.NEW_CONCEPT)
|
|
|
|
def test_bnf_node_parsers_are_updated_when_concepts_are_modified(self):
|
|
init = [
|
|
"def concept number",
|
|
"def concept one",
|
|
"def concept twenties from bnf 'twenty' number as 20 + number",
|
|
]
|
|
sheerka = self.init_scenario(init)
|
|
|
|
res = sheerka.evaluate_user_input("twenty one")
|
|
assert len(res) > 1
|
|
|
|
sheerka.evaluate_user_input("set_isa(one, number)")
|
|
res = sheerka.evaluate_user_input("twenty one")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
|
|
|
|
class TestSheerkaNonRegFile(TestUsingFileBasedSheerka):
|
|
def test_i_can_def_several_concepts(self):
|
|
sheerka = self.get_sheerka()
|
|
sheerka.evaluate_user_input("def concept foo")
|
|
|
|
sheerka = self.get_sheerka()
|
|
res = sheerka.evaluate_user_input("def concept bar")
|
|
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert res[0].body.body.id == "1002"
|
|
|
|
def test_i_can_create_concept_with_bnf_definition(self):
|
|
sheerka = self.get_sheerka()
|
|
concept_a = self.bnf_concept("a", expression=OrderedChoice(StrMatch("one"), StrMatch("two")))
|
|
sheerka.create_new_concept(self.get_context(sheerka), concept_a)
|
|
|
|
res = sheerka.evaluate_user_input("def concept plus from bnf a ('plus' plus)?")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].value, BuiltinConcepts.NEW_CONCEPT)
|
|
|
|
saved_concept = sheerka.sdp.get(sheerka.CONCEPTS_BY_KEY_ENTRY, "plus")
|
|
assert saved_concept.key == "plus"
|
|
assert saved_concept.metadata.definition == "a ('plus' plus)?"
|
|
assert "a" in saved_concept.values
|
|
assert "plus" in saved_concept.values
|
|
|
|
expected_bnf = Sequence(
|
|
ConceptExpression(concept_a, rule_name="a"),
|
|
Optional(Sequence(StrMatch("plus"), ConceptExpression("plus"))))
|
|
|
|
new_concept = res[0].value.body
|
|
assert new_concept.metadata.name == "plus"
|
|
assert new_concept.metadata.definition == "a ('plus' plus)?"
|
|
assert new_concept.bnf == expected_bnf
|
|
assert "a" in new_concept.values
|
|
assert "plus" in new_concept.values
|
|
|
|
def test_i_can_recognize_bnf_definitions_from_separate_instances(self):
|
|
sheerka = self.get_sheerka()
|
|
concept_a = sheerka.evaluate_user_input("def concept a from bnf 'one' 'two'")[0].body.body
|
|
|
|
sheerka = self.get_sheerka()
|
|
res = sheerka.evaluate_user_input("one two")
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].value, concept_a)
|
|
|
|
# add another bnf definition
|
|
concept_b = sheerka.evaluate_user_input("def concept b from bnf a 'three'")[0].body.body
|
|
|
|
sheerka = self.get_sheerka()
|
|
res = sheerka.evaluate_user_input("one two") # previous one still works
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].value, concept_a)
|
|
|
|
res = self.get_sheerka().evaluate_user_input("one two three") # new one works
|
|
assert len(res) == 1
|
|
assert res[0].status
|
|
assert sheerka.isinstance(res[0].value, concept_b)
|
|
|
|
evaluated = sheerka.evaluate_concept(self.get_context(eval_body=True), res[0].value)
|
|
assert evaluated.body == "one two three"
|
|
assert evaluated.get_value("a") == sheerka.new(concept_a.key, body="one two").init_key()
|
|
|
|
def test_i_can_eval_sophisticated_bnf_concepts_after_restart(self):
|
|
self.init_scenario([
|
|
"def concept one as 1",
|
|
"def concept number",
|
|
"set_isa(one, number)",
|
|
"def concept twenty as 20",
|
|
"set_isa(twenty, number)",
|
|
"def concept twenties from bnf twenty number where number < 10 as twenty + number",
|
|
"set_isa(twenties, number)",
|
|
"def concept thirty as 30",
|
|
"set_isa(thirty, number)",
|
|
"def concept thirties from bnf thirty number where number < 10 as thirty + number",
|
|
"set_isa(thirties, number)",
|
|
])
|
|
|
|
sheerka = self.get_sheerka() # another instance
|
|
|
|
assert sheerka.evaluate_user_input("eval twenty one")[0].body == 21
|
|
assert sheerka.evaluate_user_input("eval thirty one")[0].body == 31
|