-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Add Translator unit tests (#17)
* chore: Add Rule Generator unit tests * chore: Fix formatting * chore: Add more Rule Generator unit tests * chore: Make rule predicate a constant * chore: Add Eval Translator unit tests
- Loading branch information
1 parent
94f2366
commit 231d627
Showing
7 changed files
with
410 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,59 @@ | ||
from typing import List | ||
from typing import Dict, List, Optional, Type | ||
|
||
from json_logic_asp.adapters.asp.asp_statements import ShowStatement | ||
from json_logic_asp.constants.asp_naming import PredicateNames | ||
from json_logic_asp.models.translator_dto import DataInput, RuleInput, RuleOutput | ||
from json_logic_asp.translator.data_generator import generate_single_data_asp_definition | ||
from json_logic_asp.translator.rule_generator import generate_multiple_rule_asp_definition | ||
|
||
|
||
def translate_multi_rule_eval( | ||
rule_inputs: List[RuleInput], data_input: DataInput, with_comments: bool = False | ||
rule_inputs: List[RuleInput], | ||
data_input: DataInput, | ||
with_comments: bool = False, | ||
custom_nodes: Optional[Dict[str, Type]] = None, | ||
) -> RuleOutput: | ||
""" | ||
Given some rule inputs and a data input, generate the corresponding ASP definition ready to be executed. | ||
:param rule_inputs: multiple rule input objects with the rule definitions | ||
:param data_input: single data input with data to be evaluated against the rules | ||
:param with_comments: whether the returning ASP statements should include ASP comments | ||
:param custom_nodes: optional dictionary of custom nodes to support in the rule translation | ||
:return: data object with the generated ASP definition | ||
""" | ||
stmts: List[str] = [] | ||
|
||
data_str = generate_single_data_asp_definition(data_input, with_comments=with_comments) | ||
rule_str, rule_mapping = generate_multiple_rule_asp_definition(rule_inputs, with_comments=with_comments) | ||
data_str = generate_single_data_asp_definition(data_input=data_input, with_comments=with_comments) | ||
rule_str, rule_mapping = generate_multiple_rule_asp_definition( | ||
rule_inputs=rule_inputs, with_comments=with_comments, custom_nodes=custom_nodes | ||
) | ||
|
||
stmts.append(data_str) | ||
stmts.extend(data_str.split("\n")) | ||
stmts.append("") | ||
stmts.append(rule_str) | ||
stmts.extend(rule_str.split("\n")) | ||
stmts.append("") | ||
stmts.append(ShowStatement("rule", 1).to_asp_statement()) | ||
stmts.append(ShowStatement(PredicateNames.RULE, 1).to_asp_statement()) | ||
|
||
return RuleOutput( | ||
statements=stmts, | ||
rule_mapping=rule_mapping, | ||
) | ||
|
||
|
||
def translate_single_rule_eval(rule_input: RuleInput, data_input: DataInput, with_comments: bool = False) -> RuleOutput: | ||
def translate_single_rule_eval( | ||
rule_input: RuleInput, | ||
data_input: DataInput, | ||
with_comments: bool = False, | ||
custom_nodes: Optional[Dict[str, Type]] = None, | ||
) -> RuleOutput: | ||
""" | ||
Given a rule input and a data input, generate the corresponding ASP definition ready to be executed. | ||
:param rule_input: single rule input objects with the rule definition | ||
:param data_input: single data input with data to be evaluated against the rules | ||
:param with_comments: whether the returning ASP statements should include ASP comments | ||
:param custom_nodes: optional dictionary of custom nodes to support in the rule translation | ||
:return: data object with the generated ASP definition | ||
""" | ||
return translate_multi_rule_eval(rule_inputs=[rule_input], data_input=data_input, with_comments=with_comments) | ||
return translate_multi_rule_eval( | ||
rule_inputs=[rule_input], data_input=data_input, with_comments=with_comments, custom_nodes=custom_nodes | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
from unittest.mock import patch | ||
|
||
import pytest | ||
|
||
from json_logic_asp.models.translator_dto import DataInput, RuleInput, RuleOutput | ||
from json_logic_asp.translator import translate_multi_rule_eval, translate_single_rule_eval | ||
from tests.fixtures import cuid_fixture # noqa | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"with_comments, custom_nodes", | ||
[ | ||
(False, None), | ||
(True, None), | ||
(False, {"dummy": None}), | ||
(True, {"dummy": None}), | ||
], | ||
ids=[ | ||
"simple", | ||
"with_comments", | ||
"custom_nodes", | ||
"both", | ||
], | ||
) | ||
@patch("json_logic_asp.translator.eval_translator.generate_multiple_rule_asp_definition") | ||
@patch("json_logic_asp.translator.eval_translator.generate_single_data_asp_definition") | ||
def test_translate_multi_rule_eval( | ||
mock_generate_single_data_asp_definition, mock_generate_multiple_rule_asp_definition, with_comments, custom_nodes | ||
): | ||
mock_generate_single_data_asp_definition.return_value = "var1\nvar2\nvar3" | ||
mock_generate_multiple_rule_asp_definition.return_value = "stmt1\nstmt2\nstmt3", {"a": "b", "c": "d"} | ||
|
||
ri1 = RuleInput( | ||
rule_id="test1", | ||
rule_tree={"and": {"==": [{"var": "a"}, "b"]}}, | ||
) | ||
ri2 = RuleInput( | ||
rule_id="test2", | ||
rule_tree={"or": {">": [{"var": "c"}, "d"]}}, | ||
) | ||
di = DataInput( | ||
data_id="b", | ||
data_object={ | ||
"e": "f", | ||
"g": {"h": "i"}, | ||
}, | ||
) | ||
rule_output = translate_multi_rule_eval([ri1, ri2], di, with_comments=with_comments, custom_nodes=custom_nodes) | ||
|
||
assert rule_output.statements == ["var1", "var2", "var3", "", "stmt1", "stmt2", "stmt3", "", "#show rule/1."] | ||
assert rule_output.rule_mapping == {"a": "b", "c": "d"} | ||
mock_generate_single_data_asp_definition.assert_called_once_with( | ||
data_input=di, | ||
with_comments=with_comments, | ||
) | ||
mock_generate_multiple_rule_asp_definition.assert_called_once_with( | ||
rule_inputs=[ri1, ri2], | ||
with_comments=with_comments, | ||
custom_nodes=custom_nodes, | ||
) | ||
|
||
|
||
def test_translate_multi_rule_eval_simple(): | ||
ri1 = RuleInput( | ||
rule_id="test1", | ||
rule_tree={"and": {"==": [{"var": "a"}, "b"]}}, | ||
) | ||
ri2 = RuleInput( | ||
rule_id="test2", | ||
rule_tree={"or": {">": [{"var": "c"}, "d"]}}, | ||
) | ||
di = DataInput( | ||
data_id="e", | ||
data_object={ | ||
"f": "g", | ||
"h": {"i": "j"}, | ||
}, | ||
) | ||
|
||
rule_output = translate_multi_rule_eval([ri1, ri2], di, with_comments=True) | ||
|
||
assert rule_output.statements == [ | ||
"% f : g", | ||
"var(s8fa14cdd754f91cc6554c9e71929cce7, sb2f5ff47436671b6e533d8dc3614845d).", | ||
"% h.i : j", | ||
"var(sd95e8ab9a13affcd43b13b0b5443d484, s363b122c528f54df4a0446b6bab05515).", | ||
"", | ||
"% a EQ b", | ||
"eq(mock2) :- var(s0cc175b9c0f1b6a831c399e269772661, V1), V1 == s92eb5ffee6ae2fec3ad71c777531578f.", | ||
"and(mock3) :- eq(mock2).", | ||
"% c GT d", | ||
"gt(mock5) :- var(s4a8a08f09d37b73795649038408b5f33, V1), V1 > s8277e0910d750195b448797616e091ad.", | ||
"or(mock6) :- gt(mock5).", | ||
"% test1", | ||
"rule(s5a105e8b9d40e1329780d62ea2265d8a) :- and(mock3).", | ||
"% test2", | ||
"rule(sad0234829205b9033196ba818f7a872b) :- or(mock6).", | ||
"", | ||
"#show rule/1.", | ||
] | ||
assert rule_output.rule_mapping == { | ||
"s5a105e8b9d40e1329780d62ea2265d8a": "test1", | ||
"sad0234829205b9033196ba818f7a872b": "test2", | ||
} | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"with_comments, custom_nodes", | ||
[ | ||
(False, None), | ||
(True, None), | ||
(False, {"dummy": None}), | ||
(True, {"dummy": None}), | ||
], | ||
ids=[ | ||
"simple", | ||
"with_comments", | ||
"custom_nodes", | ||
"both", | ||
], | ||
) | ||
@patch("json_logic_asp.translator.eval_translator.translate_multi_rule_eval") | ||
def test_translate_single_rule_eval(mock_translate_multi_rule_eval, with_comments, custom_nodes): | ||
mock_ro = RuleOutput( | ||
statements=[], | ||
rule_mapping={}, | ||
) | ||
mock_translate_multi_rule_eval.return_value = mock_ro | ||
|
||
ri = RuleInput( | ||
rule_id="a", | ||
rule_tree={"c": "d"}, | ||
) | ||
di = DataInput( | ||
data_id="b", | ||
data_object={ | ||
"e": "f", | ||
"g": {"h": "i"}, | ||
}, | ||
) | ||
rule_output = translate_single_rule_eval(ri, di, with_comments=with_comments, custom_nodes=custom_nodes) | ||
|
||
assert rule_output == mock_ro | ||
mock_translate_multi_rule_eval.assert_called_once_with( | ||
rule_inputs=[ri], | ||
data_input=di, | ||
with_comments=with_comments, | ||
custom_nodes=custom_nodes, | ||
) | ||
|
||
|
||
def test_translate_single_rule_eval_simple(): | ||
ri = RuleInput( | ||
rule_id="test", | ||
rule_tree={"and": {"==": [{"var": "a"}, "b"]}}, | ||
) | ||
di = DataInput( | ||
data_id="b", | ||
data_object={ | ||
"e": "f", | ||
"g": {"h": "i"}, | ||
}, | ||
) | ||
|
||
rule_output = translate_single_rule_eval(ri, di, with_comments=True) | ||
|
||
assert rule_output.statements == [ | ||
"% e : f", | ||
"var(se1671797c52e15f763380b45e841ec32, s8fa14cdd754f91cc6554c9e71929cce7).", | ||
"% g.h : i", | ||
"var(s08a6c56ffa6dc13f368e7e73c0ca58ec, s865c0c0b4ab0e063e5caa3387c1a8741).", | ||
"", | ||
"% a EQ b", | ||
"eq(mock2) :- var(s0cc175b9c0f1b6a831c399e269772661, V1), V1 == s92eb5ffee6ae2fec3ad71c777531578f.", | ||
"and(mock3) :- eq(mock2).", | ||
"% test", | ||
"rule(s098f6bcd4621d373cade4e832627b4f6) :- and(mock3).", | ||
"", | ||
"#show rule/1.", | ||
] | ||
assert rule_output.rule_mapping == {"s098f6bcd4621d373cade4e832627b4f6": "test"} |
Oops, something went wrong.