import pytest from core.builtin_concepts import ReturnValueConcept, UnknownConcept from core.builtin_concepts_ids import BuiltinConcepts from core.concept import Concept from core.sheerka.services.SheerkaConceptManager import ValueNotFound from core.sheerka.services.SheerkaErrorManager import LAST_UNKNOWN_CONCEPTS, SheerkaErrorManager from core.sheerka.services.SheerkaExecute import ParserInput from core.sheerka.services.SheerkaRuleManager import NoConditionFound from evaluators.PythonEvaluator import PythonEvaluator from parsers.BaseParser import ParsingError, UnexpectedEofParsingError from parsers.BnfNodeParser import BnfNodeParser from parsers.ExactConceptParser import ExactConceptParser from parsers.PythonParser import PythonErrorNode, PythonParser from tests.TestUsingFileBasedSheerka import TestUsingFileBasedSheerka from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka def inner_errors(lst): return [e.error for e in lst] class TestSheerkaErrorManger(TestUsingMemoryBasedSheerka): @pytest.mark.parametrize("obj, expected", [ ("a string", []), (True, []), (False, []), (Concept("foo"), []), (Concept("foo", body=False).auto_init(), []), (UnknownConcept(), [UnknownConcept()]), (Concept("foo", body=UnknownConcept()).auto_init(), [UnknownConcept()]), (PythonErrorNode("msg", None), [PythonErrorNode("msg", None)]) ]) def test_i_can_get_error_for_simple_objects(self, obj, expected): sheerka, context = self.init_test().unpack() assert sheerka.get_obj_errors(context, obj) == expected def test_i_can_get_error_when_builtin_concept_in_error(self): sheerka, context = self.init_test().unpack() obj = sheerka.new(BuiltinConcepts.ONTOLOGY_ALREADY_DEFINED) assert sheerka.get_obj_errors(context, obj) == [obj] def test_i_can_get_error_when_return_value(self): sheerka, context = self.init_test().unpack() error = sheerka.err("an error") ret_val = ReturnValueConcept("Test", False, sheerka.err("an error")) assert sheerka.get_obj_errors(context, ret_val) == [error] def test_i_can_get_inner_error(self): sheerka, context = self.init_test().unpack() error = sheerka.err("an error") ret_val = ReturnValueConcept("Test", False, sheerka.err("an error")) assert sheerka.get_obj_errors(context, ret_val) == [error] def test_i_can_get_error_when_embedded_errors(self): sheerka, context = self.init_test().unpack() concept_eval_error = sheerka.new(BuiltinConcepts.CONCEPT_EVAL_ERROR) unknown_concept = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT) not_an_error = sheerka.new(BuiltinConcepts.AUTO_EVAL) error = sheerka.err([concept_eval_error, unknown_concept, not_an_error]) ret_val = ReturnValueConcept("Test", False, error) errors_found = sheerka.get_obj_errors(context, ret_val) assert errors_found == [error, concept_eval_error, unknown_concept] def test_i_can_get_embedded_errors_from_get_error_method(self): sheerka, context = self.init_test().unpack() embedded_error = NotImplementedError() error = sheerka.new(BuiltinConcepts.NOT_FOR_ME, body="some text", reason=embedded_error) ret_val = ReturnValueConcept("Test", False, error) errors_found = sheerka.get_obj_errors(context, ret_val) assert errors_found == [error, embedded_error] def test_i_can_get_error_from_list(self): sheerka, context = self.init_test().unpack() concept_eval_error = sheerka.new(BuiltinConcepts.CONCEPT_EVAL_ERROR) unknown_concept = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT) not_an_error = sheerka.new(BuiltinConcepts.AUTO_EVAL) error = sheerka.err([concept_eval_error, unknown_concept, not_an_error]) ret_val_1 = ReturnValueConcept("Test", False, error) python_error = PythonErrorNode("msg", Exception()) value_not_found = ValueNotFound("item", "value") multiple_error = sheerka.new(BuiltinConcepts.MULTIPLE_ERRORS, body=[python_error, value_not_found]) ret_val_2 = ReturnValueConcept("Test", False, multiple_error) errors_found = sheerka.get_obj_errors(context, [ret_val_1, ret_val_2]) assert errors_found == [error, concept_eval_error, unknown_concept, multiple_error, python_error, value_not_found] def test_i_can_filter_error_by_concept_key(self): sheerka, context = self.init_test().unpack() concept_eval_error = sheerka.new(BuiltinConcepts.CONCEPT_EVAL_ERROR) unknown_concept = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT) python_error = PythonErrorNode("msg", Exception()) error = sheerka.err([concept_eval_error, unknown_concept, python_error]) ret_val = ReturnValueConcept("Test", False, error) errors_found = sheerka.get_obj_errors(context, ret_val, __type=BuiltinConcepts.CONCEPT_EVAL_ERROR) assert errors_found == [concept_eval_error] def test_i_can_filter_error_by_class_name(self): sheerka, context = self.init_test().unpack() concept_eval_error = sheerka.new(BuiltinConcepts.CONCEPT_EVAL_ERROR) unknown_concept = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT) python_error = PythonErrorNode("msg", Exception()) error = sheerka.err([concept_eval_error, unknown_concept, python_error]) ret_val = ReturnValueConcept("Test", False, error) errors_found = sheerka.get_obj_errors(context, ret_val, __type="PythonErrorNode") assert errors_found == [python_error] def test_i_can_filter_error_by_concept_attribute(self): sheerka, context = self.init_test().unpack() concept_eval_error = sheerka.new(BuiltinConcepts.CONCEPT_EVAL_ERROR) unknown_concept = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT, concept_ref="a_concept_ref") python_error = PythonErrorNode("msg", Exception()) error = sheerka.err([concept_eval_error, unknown_concept, python_error]) ret_val = ReturnValueConcept("Test", False, error) errors_found = sheerka.get_obj_errors(context, ret_val, concept_ref="a_concept_ref") assert errors_found == [unknown_concept] def test_i_can_filter_error_by_class_attribute(self): sheerka, context = self.init_test().unpack() concept_eval_error = sheerka.new(BuiltinConcepts.CONCEPT_EVAL_ERROR) unknown_concept = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT, concept_ref="a_concept_ref") python_error = PythonErrorNode("error source", Exception()) error = sheerka.err([concept_eval_error, unknown_concept, python_error]) ret_val = ReturnValueConcept("Test", False, error) errors_found = sheerka.get_obj_errors(context, ret_val, source="error source") assert errors_found == [python_error] def test_i_can_filter_error_by_exception_name_and_type(self): sheerka, context = self.init_test().unpack() from evaluators.PythonEvaluator import PythonEvalError name_error = NameError("foo") python_eval_error = PythonEvalError(name_error, "foo", None, None) error = sheerka.err([python_eval_error]) ret_val = ReturnValueConcept("Test", False, error) errors_found = sheerka.get_obj_errors(context, ret_val, __type="NameError") assert errors_found == [name_error] errors_found = sheerka.get_obj_errors(context, ret_val, __type=NameError) assert errors_found == [name_error] def test_i_can_filter_error_on_multiple_criteria(self): sheerka, context = self.init_test().unpack() concept_eval_error = sheerka.new(BuiltinConcepts.CONCEPT_EVAL_ERROR) unknown_concept = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT, concept_ref="a_concept_ref") value_not_found = ValueNotFound("an_item", "a value") error = sheerka.err([concept_eval_error, unknown_concept, value_not_found]) ret_val = ReturnValueConcept("Test", False, error) errors_found = sheerka.get_obj_errors(context, ret_val, __type="ValueNotFound", item="an_item", value="a value") assert errors_found == [value_not_found] def test_i_cannot_get_error_when_return_value_s_status_is_true(self): sheerka, context = self.init_test().unpack() ret_val = ReturnValueConcept("Test", True, sheerka.err("an error")) assert sheerka.get_obj_errors(context, ret_val) == [] def test_i_can_get_error_items(self): sheerka, context = self.init_test().unpack() service = sheerka.services[SheerkaErrorManager.NAME] simple_error = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT, body=Concept("foo")) ret1 = sheerka.ret("Test1", False, simple_error) sub_error_is_an_exception = sheerka.new(BuiltinConcepts.NOT_FOR_ME, reason=NotImplementedError()) ret2 = sheerka.ret("Test2", False, sub_error_is_an_exception) inner_error = sheerka.err([ParsingError(), UnexpectedEofParsingError("EOF", 0)]) sub_error_is_an_error = sheerka.new(BuiltinConcepts.NOT_FOR_ME, reason=inner_error) ret3 = sheerka.ret("Test3", False, sub_error_is_an_error) parsing_error = sheerka.new(BuiltinConcepts.PARSER_RESULT, parser=PythonParser(), source="not a valid source", body="Not totally valid parsing") ret4 = sheerka.ret("Test4", False, parsing_error) multiple_level_errors1 = sheerka.err("Err1") multiple_level_errors2 = sheerka.err(multiple_level_errors1) multiple_level_errors3 = sheerka.err(multiple_level_errors2) ret5 = sheerka.ret("Test5", False, multiple_level_errors3) filtered = sheerka.new(BuiltinConcepts.FILTERED, reason="not really given") ret6 = sheerka.ret("Test6", False, filtered) ret7 = sheerka.ret("Test5", True, None) error_items = list(service.get_errors_items([ret1, ret2, ret3, ret4, ret5, ret6, ret7])) assert len(error_items) == 6 # ret1 : simple_error assert len(error_items[0].children) == 0 # ret2 : sub_error_is_an_exception assert len(error_items[1].children) == 1 assert len(error_items[1].children[0].children) == 0 # ret3 : inner_error assert len(error_items[2].children) == 1 assert len(error_items[2].children[0].children) == 2 assert len(error_items[2].children[0].children[0].children) == 0 assert len(error_items[2].children[0].children[1].children) == 0 # ret4 : parsing_error assert len(error_items[3].children) == 0 # ret5 : multiple_level_errors assert len(error_items[4].children) == 1 assert len(error_items[4].children[0].children) == 1 assert len(error_items[4].children[0].children[0].children) == 0 # ret6 Filtered without a real reason assert len(error_items[5].children) == 0 def test_i_can_get_all_error_items(self): sheerka, context = self.init_test().unpack() service = sheerka.services[SheerkaErrorManager.NAME] simple_error = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT, body=Concept("foo")) ret1 = sheerka.ret("Test1", False, simple_error) inner_error = sheerka.err([ParsingError(), UnexpectedEofParsingError("EOF", 0)]) sub_error_is_an_error = sheerka.new(BuiltinConcepts.NOT_FOR_ME, reason=inner_error) ret2 = sheerka.ret("Test3", False, sub_error_is_an_error) multiple_level_errors1 = sheerka.err("Err1") multiple_level_errors2 = sheerka.err(multiple_level_errors1) multiple_level_errors3 = sheerka.err(multiple_level_errors2) ret3 = sheerka.ret("Test5", False, multiple_level_errors3) all_error_items = list(service.get_all_error_items([ret1, ret2, ret3])) assert len(all_error_items) == 8 def test_i_can_keep_the_correct_error_source(self): sheerka, context = self.init_test().unpack() service = sheerka.services[SheerkaErrorManager.NAME] simple_error = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT, body=Concept("foo")) ret1 = sheerka.ret("Source1", False, simple_error) sub_error_is_an_exception = sheerka.new(BuiltinConcepts.NOT_FOR_ME, reason=NotImplementedError()) ret2 = sheerka.ret("Source2", False, sub_error_is_an_exception) multiple_errors = sheerka.new(BuiltinConcepts.MULTIPLE_ERRORS, body=[ret1, ret2]) ret3 = sheerka.ret("Source3", False, multiple_errors) error_items = list(service.get_errors_items([ret3])) assert len(error_items) == 1 assert error_items[0].source == "Source3" assert error_items[0].children[0].source == "Source1" assert error_items[0].children[1].source == "Source2" def test_i_can_get_filtered_error_explanation(self): sheerka, context = self.init_test().unpack() service = sheerka.services[SheerkaErrorManager.NAME] simple_error = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT, body=Concept("foo")) ret1 = sheerka.ret("Test1", False, simple_error) sub_error_is_an_exception = sheerka.new(BuiltinConcepts.NOT_FOR_ME, reason=NotImplementedError()) ret2 = sheerka.ret("Test2", False, sub_error_is_an_exception) context.add_values(return_values=[ret1, ret2]) service.on_user_input_evaluated(context) res = sheerka.get_last_errors(context) assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION) assert len(res.body) == 3 res = sheerka.get_last_errors(context, __type=BuiltinConcepts.UNKNOWN_CONCEPT) assert sheerka.isinstance(res, BuiltinConcepts.EXPLANATION) assert len(res.body) == 1 def test_i_cannot_recognize_error_when_no_error(self): sheerka, context = self.init_test().unpack() res = sheerka.recognize_error(context, "Some error") assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND) def test_i_can_recognized_error_when_error_is_a_builtin_concept(self): sheerka, context = self.init_test().unpack() service = sheerka.services[SheerkaErrorManager.NAME] simple_error = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT, body=Concept("foo")) ret1 = sheerka.ret("Test1", False, simple_error) context.add_values(return_values=[ret1]) service.on_user_input_evaluated(context) assert sheerka.recognize_error(context, __type=BuiltinConcepts.UNKNOWN_CONCEPT) assert sheerka.recognize_error(context, __type=UnknownConcept) assert sheerka.recognize_error(context, __type="UnknownConcept") assert sheerka.recognize_error(context, BuiltinConcepts.UNKNOWN_CONCEPT) assert sheerka.recognize_error(context, UnknownConcept) assert sheerka.recognize_error(context, "UnknownConcept") assert sheerka.recognize_error(context, f"self.name == '{BuiltinConcepts.UNKNOWN_CONCEPT}'") assert sheerka.recognize_error(context, f"get_type(self) == '{BuiltinConcepts.UNKNOWN_CONCEPT}'") def test_i_can_recognized_error_when_error_is_a_error_ErrorObj(self): sheerka, context = self.init_test().unpack() service = sheerka.services[SheerkaErrorManager.NAME] simple_error = sheerka.new(BuiltinConcepts.ERROR, body=NoConditionFound()) ret1 = sheerka.ret("Test1", False, simple_error) context.add_values(return_values=[ret1]) service.on_user_input_evaluated(context) assert sheerka.recognize_error(context, __type=NoConditionFound) assert sheerka.recognize_error(context, __type="NoConditionFound") def test_i_cannot_recognize_unknown_concept_when_no_error(self): sheerka, context = self.init_test().unpack() res = sheerka.has_unknown_concepts(context) assert sheerka.isinstance(res, BuiltinConcepts.NOT_FOUND) def test_i_can_manage_direct_unknown_concept(self): sheerka, context = self.init_test().unpack() service = sheerka.services[SheerkaErrorManager.NAME] exact_concept_parser = ExactConceptParser() # a simple unknown concept ret = exact_concept_parser.parse(context, ParserInput("foo bar")) context.add_values(return_values=[ret]) service.on_user_input_evaluated(context) assert sheerka.has_unknown_concepts(context) assert sheerka.get_from_memory(context, LAST_UNKNOWN_CONCEPTS).obj == "foo bar" def test_i_can_manage_multiple_direct_unknown_concept(self): sheerka, context = self.init_test().unpack() service = sheerka.services[SheerkaErrorManager.NAME] exact_concept_parser = ExactConceptParser() # a simple unknown concept ret1 = exact_concept_parser.parse(context, ParserInput("foo")) ret2 = exact_concept_parser.parse(context, ParserInput("bar")) context.add_values(return_values=[ret1, ret2]) service.on_user_input_evaluated(context) assert sheerka.has_unknown_concepts(context) assert sheerka.get_from_memory(context, LAST_UNKNOWN_CONCEPTS).obj == {"foo", "bar"} @pytest.mark.parametrize("source, expected", [ ("foo bar", "foo"), ("bar foo", "foo"), ("foo bar baz", {"foo", "baz"}), ("my foo bar my baz", {"my foo", "my baz"}), ]) def test_i_can_manage_unknown_concept_when_parts_are_recognized(self, source, expected): sheerka, context, foo = self.init_concepts("bar") service = sheerka.services[SheerkaErrorManager.NAME] exact_concept_parser = ExactConceptParser() ret1 = exact_concept_parser.parse(context, ParserInput(source)) context.add_values(return_values=[ret1]) service.on_user_input_evaluated(context) assert sheerka.has_unknown_concepts(context) assert sheerka.get_from_memory(context, LAST_UNKNOWN_CONCEPTS).obj == expected def test_i_can_manage_multiple_unknown_concept_when_parts_are_recognized(self): sheerka, context, foo = self.init_concepts("bar") service = sheerka.services[SheerkaErrorManager.NAME] exact_concept_parser = ExactConceptParser() ret1 = exact_concept_parser.parse(context, ParserInput("foo bar")) ret2 = exact_concept_parser.parse(context, ParserInput("my foo bar my baz")) context.add_values(return_values=[ret1, ret2]) service.on_user_input_evaluated(context) assert sheerka.has_unknown_concepts(context) assert sheerka.get_from_memory(context, LAST_UNKNOWN_CONCEPTS).obj == {"foo", "my foo", "my baz"} def test_i_can_manage_unknown_concept_from_name_error(self): sheerka, context = self.init_test().unpack() service = sheerka.services[SheerkaErrorManager.NAME] python_parser = PythonParser() python_evaluator = PythonEvaluator() # ret = python_parser.parse(context, ParserInput("foo")) ret = python_evaluator.eval(context, ret) context.add_values(return_values=[ret]) service.on_user_input_evaluated(context) assert sheerka.has_unknown_concepts(context) assert sheerka.get_from_memory(context, LAST_UNKNOWN_CONCEPTS).obj == "foo" def test_i_can_manage_unknown_concept_from_bnf_error(self): sheerka, context, quantify_x = self.init_concepts( Concept("quantify x", definition="('one' | 'two')=unit x").def_var("x"), create_new=True ) service = sheerka.services[SheerkaErrorManager.NAME] bnf_node_parser = BnfNodeParser() # a simple unknown concept ret = bnf_node_parser.parse(context, ParserInput("one foo")) context.add_values(return_values=[ret]) service.on_user_input_evaluated(context) assert sheerka.has_unknown_concepts(context) assert sheerka.get_from_memory(context, LAST_UNKNOWN_CONCEPTS).obj == "foo" class TestFileBasedSheerkaErrorManger(TestUsingFileBasedSheerka): def test_i_can_remember_last_error(self): sheerka = self.get_sheerka() context = self.get_context(message="TestingErrorManagement::get_last_errors()") service = sheerka.services[SheerkaErrorManager.NAME] simple_error = sheerka.new(BuiltinConcepts.UNKNOWN_CONCEPT, body=Concept("foo")) ret1 = sheerka.ret("Test1", False, simple_error) sub_error_is_an_exception = sheerka.new(BuiltinConcepts.NOT_FOR_ME, reason=NotImplementedError()) ret2 = sheerka.ret("Test2", False, sub_error_is_an_exception) context.add_values(return_values=[ret1, ret2]) service.on_user_input_evaluated(context) new_context = self.get_context(sheerka) explanations = sheerka.get_last_errors(new_context) self.commit(context) assert sheerka.isinstance(explanations, BuiltinConcepts.EXPLANATION) assert len(explanations.body) == 3 assert service.last_detected_errors_event_id == context.event.get_digest() assert service.last_detected_errors_event_message == context.event.message assert service.current_errors_event_id == context.event.get_digest() assert service.current_errors_event_message == context.event.message sheerka = self.new_sheerka_instance() service = sheerka.services[SheerkaErrorManager.NAME] assert service.last_detected_errors_event_id == context.event.get_digest() assert service.last_detected_errors_event_message == context.event.message assert service.current_errors_event_id == context.event.get_digest() assert service.current_errors_event_message == context.event.message self.reset_hard_test_env()