from dataclasses import dataclass import pytest from core.builtin_concepts import BuiltinConcepts from core.concept import Concept, ConceptParts from core.sheerka.services.SheerkaFilter import Pipe, SheerkaFilter from printer.Formatter import Formatter, BraceToken from printer.SheerkaPrinter import FormatInstructions from tests.TestUsingMemoryBasedSheerka import TestUsingMemoryBasedSheerka @dataclass class Obj: a: object b: object @dataclass() class ObjLongProp: first_property_name: object second: object class TestSheerkaPrinter(TestUsingMemoryBasedSheerka): @pytest.mark.parametrize("text, expected", [ ("Hello world!", "Hello world!\n"), ("%black%%red%%green%%yellow%%reset%", "\x1b[30m\x1b[31m\x1b[32m\x1b[33m\x1b[0m\n"), ("%blue%%magenta%%cyan%%white%%reset%", "\x1b[34m\x1b[35m\x1b[36m\x1b[37m\x1b[0m\n"), (["Hello", "world!"], "Hello\nworld!\n"), (("Hello", "world!"), "Hello\nworld!\n"), ]) def test_i_can_print(self, capsys, text, expected): sheerka = self.get_sheerka() sheerka.print(text) captured = capsys.readouterr() assert captured.out == expected def test_i_can_disable_color(self, capsys): sheerka = self.get_sheerka() sheerka.print("%red%Hello world !%reset%", FormatInstructions(no_color=True)) captured = capsys.readouterr() assert captured.out == "Hello world !\n" def test_i_can_print_concept(self, capsys): sheerka = self.get_sheerka() foo = Concept("foo a b").def_var("a").def_var("b") sheerka.print(foo) captured = capsys.readouterr() assert captured.out == str(foo) + "\n" def test_i_can_use_custom_format(self, capsys): sheerka = self.get_sheerka() foo = Concept("foo a b").def_var("a").def_var("b").init_key() sheerka.printer_handler.register_custom_printer( foo, lambda printer, instr, item: printer.fp(instr, f"foo a={item.a}, b={item.b}")) foo.set_value("a", "value a").set_value("b", "value b") sheerka.print(foo) captured = capsys.readouterr() assert captured.out == "foo a=value a, b=value b\n" def test_i_can_print_and_recurse(self, capsys): sheerka = self.get_sheerka() level3 = Concept("level3") level2 = Concept("level2").set_value(ConceptParts.BODY, level3) level1 = Concept("level1").set_value(ConceptParts.BODY, level2) sheerka.print(level1) captured = capsys.readouterr() assert captured.out == f"{level1}\n" sheerka.print(level1, FormatInstructions().set_recurse("body", 1)) captured = capsys.readouterr() assert captured.out == f"{level1}\n {level2}\n" sheerka.print(level1, FormatInstructions().set_recurse("body", 2)) captured = capsys.readouterr() assert captured.out == f"{level1}\n {level2}\n {level3}\n" sheerka.print(level1, FormatInstructions().set_recurse("body", 10)) captured = capsys.readouterr() assert captured.out == f"{level1}\n {level2}\n {level3}\n" def test_i_can_print_and_recurse_list(self, capsys): sheerka = self.get_sheerka() level31 = Concept("level31") level32 = Concept("level32") level33 = Concept("level33") level21 = Concept("level21").set_value(ConceptParts.BODY, [level31, level32]) level22 = Concept("level22").set_value(ConceptParts.BODY, [level33]) level1 = Concept("level1").set_value(ConceptParts.BODY, [level21, level22]) sheerka.print(level1) captured = capsys.readouterr() assert captured.out == f"{level1}\n" sheerka.print(level1, FormatInstructions().set_recurse("body", 1)) captured = capsys.readouterr() assert captured.out == f"{level1}\n {level21}\n {level22}\n" sheerka.print(level1, FormatInstructions().set_recurse("body", 3)) captured = capsys.readouterr() assert captured.out == f"{level1}\n {level21}\n {level31}\n {level32}\n {level22}\n {level33}\n" def test_explanation_concept_can_control_recursion(self, capsys): sheerka = self.get_sheerka() level31 = Concept("level31") level32 = Concept("level32") level33 = Concept("level33") level21 = Concept("level21").set_value(ConceptParts.BODY, [level31, level32]) level22 = Concept("level22").set_value(ConceptParts.BODY, [level33]) level1 = Concept("level1").set_value(ConceptParts.BODY, [level21, level22]) instructions = FormatInstructions(no_color=True) explanation = sheerka.new( BuiltinConcepts.EXPLANATION, digest="digest", command="command", title="title", instructions=instructions, body=[level1]) sheerka.print(explanation) captured = capsys.readouterr() assert captured.out == f"digest : command\n(None)level1\n" instructions = FormatInstructions(no_color=True).set_recurse("body", 2) explanation = sheerka.new( BuiltinConcepts.EXPLANATION, digest="digest", command="command", title="title", instructions=instructions, body=[level1]) sheerka.print(explanation) captured = capsys.readouterr() assert captured.out == """digest : command (None)level1 (None)level21 (None)level31 (None)level32 (None)level22 (None)level33 """ def test_i_can_format_l_concepts_using_default_format_l_definition(self, capsys): # default format_l definition # for all obj of a given type sheerka = self.get_sheerka() foo = Concept("foo a b").def_var("a").def_var("b").init_key() foo.set_value("a", "value a").set_value("b", "value b") foo.set_value(ConceptParts.BODY, "body") sheerka.set_id_if_needed(foo, False) sheerka.printer_handler.register_format_l(foo, "DEFAULT:{id}-{name}-{key}-{body}-{a}-{b}") sheerka.print(foo) captured = capsys.readouterr() assert captured.out == "DEFAULT:1001-foo a b-foo __var__0 __var__1-body-value a-value b\n" def test_i_can_format_l_concepts_using_context_format_l_definition(self, capsys): # context format_l definition # for all obj of a given type in the current print call sheerka = self.get_sheerka() foo = Concept("foo a b").def_var("a").def_var("b").init_key() foo.set_value("a", "value a").set_value("b", "value b") foo.set_value(ConceptParts.BODY, "body") sheerka.set_id_if_needed(foo, False) sheerka.printer_handler.register_format_l(foo, "DEFAULT:{id}-{name}-{key}-{body}-{a}-{b}") context_instructions = FormatInstructions().set_format_l(foo, "CONTEXT:{id}-{name}-{key}-{body}-{a}-{b}") sheerka.print(foo, context_instructions) captured = capsys.readouterr() assert captured.out == "CONTEXT:1001-foo a b-foo __var__0 __var__1-body-value a-value b\n" def test_i_can_format_l_concepts_using_item_format_l_definition(self, capsys): # item format_l definition # for the item only sheerka = self.get_sheerka() foo = Concept("foo a b").def_var("a").def_var("b").init_key() foo.set_value("a", "value a").set_value("b", "value b") foo.set_value(ConceptParts.BODY, "body") sheerka.set_id_if_needed(foo, False) sheerka.printer_handler.register_format_l(foo, "{id}-{name}-{key}-{body}-{a}-{b}") context_instructions = FormatInstructions().set_format_l(foo, "CONTEXT:{id}-{name}-{key}-{body}-{a}-{b}") item_instructions = FormatInstructions().set_format_l(foo, "ITEM:{id}-{name}-{key}-{body}-{a}-{b}") foo.set_prop(BuiltinConcepts.FORMAT_INSTRUCTIONS, item_instructions) sheerka.print(foo, context_instructions) captured = capsys.readouterr() assert captured.out == "ITEM:1001-foo a b-foo __var__0 __var__1-body-value a-value b\n" def test_i_can_format_l_objects(self, capsys): sheerka = self.get_sheerka() foo = Obj("value a", "value b") sheerka.printer_handler.register_format_l(foo, "{a}-{b}") sheerka.print(foo) captured = capsys.readouterr() assert captured.out == "value a-value b\n" def test_i_can_format_l_execution_context(self, capsys): # In this test, no format_l definition is provided # The system knows how to format ExecutionContext sheerka = self.get_sheerka() context = self.get_context(sheerka) execution_context = context.push(BuiltinConcepts.NOP, None, who="test_sheerka_printer", desc="Testing Execution Context Printing") ret_val = sheerka.ret("test_sheerka_printer", True, sheerka.new(BuiltinConcepts.SUCCESS)) execution_context.add_values(return_value=ret_val) ec = execution_context.as_bag() sheerka.print(execution_context) captured = capsys.readouterr() assert captured.out == f"[{ec['id']:3}] {ec['desc']} ({ec['status']})\n" def test_i_can_register_a_custom_format_by_its_name(self, capsys): sheerka = self.get_sheerka() foo = Obj("value a", "value b") sheerka.printer_handler.register_format_l("tests.core.test_sheerka_printer.Obj", "{a}-{b}") sheerka.print(foo) captured = capsys.readouterr() assert captured.out == "value a-value b\n" def test_i_can_format_d_concepts_using_default_definition(self, capsys): sheerka, context, foo = self.init_concepts(Concept("foo a b").def_var("a").def_var("b")) foo_1 = sheerka.new(foo.key, a="value a", b="value b") foo_2 = sheerka.new(foo.key, a="value c", b="value d") lst = [foo_1, foo_2] sheerka.printer_handler.register_format_d(foo, {"a": "DEFAULT:{a}", "b": "DEFAULT:{b}"}) sheerka.print(lst) captured = capsys.readouterr() assert captured.out == """(1001)foo a b a: DEFAULT:'value a' b: DEFAULT:'value b' (1001)foo a b a: DEFAULT:'value c' b: DEFAULT:'value d' """ def test_i_can_format_d_concepts_using_context_definition(self, capsys): sheerka, context, foo = self.init_concepts(Concept("foo a b").def_var("a").def_var("b")) foo_1 = sheerka.new(foo.key, a="value a", b="value b") foo_2 = sheerka.new(foo.key, a="value c", b="value d") lst = [foo_1, foo_2] sheerka.printer_handler.register_format_d(foo, {"a": "DEFAULT:{a}", "b": "DEFAULT:{b}"}) context_instructions = FormatInstructions().set_format_d(foo, {"a": "CONTEXT:{a}", "b": "CONTEXT:{b}"}) sheerka.print(lst, context_instructions) captured = capsys.readouterr() assert captured.out == """(1001)foo a b a: CONTEXT:'value a' b: CONTEXT:'value b' (1001)foo a b a: CONTEXT:'value c' b: CONTEXT:'value d' """ def test_i_can_format_d_concepts_using_item_definition(self, capsys): sheerka, context, foo = self.init_concepts(Concept("foo a b").def_var("a").def_var("b")) item_instructions = FormatInstructions().set_format_d(foo, {"a": "ITEM:{a}", "b": "ITEM:{b}"}) foo.set_format_instructions(item_instructions) foo_1 = sheerka.new(foo.key, a="value a", b="value b") foo_2 = sheerka.new(foo.key, a="value c", b="value d") lst = [foo_1, foo_2] sheerka.printer_handler.register_format_d(foo, {"a": "DEFAULT:{a}", "b": "DEFAULT:{b}"}) context_instructions = FormatInstructions().set_format_d(foo, {"a": "CONTEXT:{a}", "b": "CONTEXT:{b}"}) # Note that this time, foo has a format instruction defined sheerka.print(lst, context_instructions) captured = capsys.readouterr() assert captured.out == """(1001)foo a b a: ITEM:'value a' b: ITEM:'value b' (1001)foo a b a: ITEM:'value c' b: ITEM:'value d' """ def test_i_can_format_d_objects(self, capsys): sheerka = self.get_sheerka() foo = [Obj("value a", "value b"), Obj("value c", "value d")] sheerka.printer_handler.register_format_d(Obj, {"a": "CUSTOM:{a}", "b": "CUSTOM:{b}"}) sheerka.print(foo) captured = capsys.readouterr() assert captured.out == """Obj(a='value a', b='value b') a: CUSTOM:'value a' b: CUSTOM:'value b' Obj(a='value c', b='value d') a: CUSTOM:'value c' b: CUSTOM:'value d' """ def test_i_can_format_d_with_only_a_list_of_properties(self, capsys): sheerka = self.get_sheerka() foo = [Obj("value a", "value b"), Obj("value c", "value d")] sheerka.printer_handler.register_format_d(Obj, ["a", "b"]) sheerka.print(foo) captured = capsys.readouterr() assert captured.out == """Obj(a='value a', b='value b') a: 'value a' b: 'value b' Obj(a='value c', b='value d') a: 'value c' b: 'value d' """ def test_i_can_format_d_and_align_properties(self, capsys): sheerka = self.get_sheerka() foo = [ObjLongProp("value a", "value b"), ObjLongProp("value c", "value d")] sheerka.printer_handler.register_format_d(ObjLongProp, ["first_property_name", "second"]) sheerka.print(foo) captured = capsys.readouterr() assert captured.out == """ObjLongProp(first_property_name='value a', second='value b') first_property_name: 'value a' second : 'value b' ObjLongProp(first_property_name='value c', second='value d') first_property_name: 'value c' second : 'value d' """ def test_i_can_format_d_all_properties_of_a_concept(self, capsys): sheerka, context, foo = self.init_concepts(Concept("foo a b").def_var("a").def_var("b")) foo_1 = sheerka.new(foo.key, a="value a", b="value b") foo_2 = sheerka.new(foo.key, a="value c", b="value d") lst = [foo_1, foo_2] sheerka.printer_handler.register_format_d(foo) sheerka.print(lst) captured = capsys.readouterr() assert captured.out == """(1001)foo a b a : 'value a' b : 'value b' id : '1001' name: 'foo a b' key : 'foo __var__0 __var__1' body: **NotInit** self: (1001)foo a b (1001)foo a b a : 'value c' b : 'value d' id : '1001' name: 'foo a b' key : 'foo __var__0 __var__1' body: **NotInit** self: (1001)foo a b """ def test_i_can_format_d_when_dictionary(self, capsys): sheerka, context, foo = self.init_concepts(Concept("foo a b").def_var("a").def_var("b")) dict_value = { "a": "value a", "beta": {"b1": 10, "b2": Obj("10", 15), "b3": ["items", "in", "a", "list"]}, "gamma": {"list": ["'quoted string'", '"double" \'single\'', "c3"], "empty": []}, "epsilon": ["a", "b", "c"], "g": {"tuple": ("tuple-a", "tuple-b", "tuple-b"), "empty": tuple()}, "h": {"set": {"set-a"}, "empty": set()}, } foo_1 = sheerka.new(foo.key, a="value a", b=dict_value) lst = [foo_1] sheerka.printer_handler.register_format_d(foo) sheerka.print(lst) captured = capsys.readouterr() assert captured.out == """(1001)foo a b a : 'value a' b : {'a' : 'value a' 'beta' : {'b1': 10 'b2': Obj(a='10', b=15) 'b3': ['items', 'in', 'a', 'list']} 'gamma' : {'list' : ["'quoted string'", ""double" 'single'", 'c3'] 'empty': []} 'epsilon': ['a', 'b', 'c'] 'g' : {'tuple': ('tuple-a', 'tuple-b', 'tuple-b') 'empty': ()} 'h' : {'set' : {'set-a'} 'empty': {}}} id : '1001' name: 'foo a b' key : 'foo __var__0 __var__1' body: **NotInit** self: (1001)foo a b """ def test_i_can_manage_when_property_does_not_exist(self, capsys): sheerka = self.get_sheerka() foo = Obj("value a", "value b") sheerka.printer_handler.register_format_d(Obj, ["foo", "bar"]) sheerka.print(foo) captured = capsys.readouterr() assert captured.out == """Obj(a='value a', b='value b') foo: *name 'foo' is not defined* bar: *name 'bar' is not defined* """ @pytest.mark.parametrize("template, expected", [ ("+-{b}", "value a-value b\n"), ("{b}-+", "value b-value a\n"), ("\\+{b}", "+value b\n"), ("{b}\\+", "value b+\n"), ("+", "+\n"), ("\\+", "\\+\n"), ]) def test_i_can_concat_print_instruction_and_register_format(self, capsys, template, expected): sheerka = self.get_sheerka() foo = Obj("value a", "value b") sheerka.printer_handler.register_format_l("tests.core.test_sheerka_printer.Obj", "{a}") instructions = FormatInstructions().set_format_l("tests.core.test_sheerka_printer.Obj", template) sheerka.print(foo, instructions) captured = capsys.readouterr() assert captured.out == expected def test_i_can_manage_exception_when_printing(self, capsys): sheerka = self.get_sheerka() filter_service = SheerkaFilter(sheerka) predicate = "self='two'" # it should be self=='two' items = ["one", "two", "three"] | Pipe(filter_service.pipe_filter)(predicate) sheerka.print(items) captured = capsys.readouterr() assert captured.out == "\x1b[31mSyntaxError: invalid syntax\nself='two'\n ^\x1b[0m\n" @pytest.mark.parametrize("template, expected", [ (None, []), ("", []), ("foo", []), ("{foo}", [BraceToken(0, 4, -1)]), ("xxx{foo}yyy", [BraceToken(3, 7, -1)]), ("{foo}{bar}-{baz}", [BraceToken(0, 4, -1), BraceToken(5, 9, -1), BraceToken(11, 15, -1)]), ("xxx{{foo}}yyy", []), ("xxx{{foo}yyy", []), ("xxx{yyy", []), ("xxx{", []), ]) def test_i_can_get_braces(self, template, expected): assert list(Formatter.braces(template)) == expected @pytest.mark.parametrize("template, expected", [ (None, None), ("", ""), ("foo", "foo"), ("{foo}", "{format_obj(foo, 0)}"), ("{foo : >16}", "{format_obj(foo , 0): >16}"), ("{foo : >16}{bar}xxx{baz}", "{format_obj(foo , 0): >16}{format_obj(bar, 0)}xxx{format_obj(baz, 0)}"), ]) def test_i_can_inject_format_obj(self, template, expected): assert Formatter.inject_format_obj(template, 0) == expected