mirror of https://github.com/nucypher/nucypher.git
Add tests for conditions lingo validation. Use InvalidConditionLingo exception for invalid lingo grammar.
parent
c50eb1e5c2
commit
2e0a1e5782
|
@ -1,4 +1,8 @@
|
|||
# Lingo Validation Errors (Grammar)
|
||||
class InvalidConditionLingo(Exception):
|
||||
"""Invalid lingo grammar."""
|
||||
|
||||
|
||||
class InvalidLogicalOperator(Exception):
|
||||
"""Invalid definition of logical lingo operator."""
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ from marshmallow import fields, post_load
|
|||
from nucypher.policy.conditions.base import ReencryptionCondition
|
||||
from nucypher.policy.conditions.context import is_context_variable
|
||||
from nucypher.policy.conditions.exceptions import (
|
||||
InvalidConditionLingo,
|
||||
InvalidLogicalOperator,
|
||||
ReturnValueEvaluationError,
|
||||
)
|
||||
|
@ -180,12 +181,18 @@ class ConditionLingo:
|
|||
@staticmethod
|
||||
def _validate_grammar(lingo) -> None:
|
||||
if len(lingo) % 2 == 0:
|
||||
raise ValueError('conditions must be odd length, ever other element being an operator')
|
||||
raise InvalidConditionLingo(
|
||||
"conditions must be odd length, ever other element being an operator"
|
||||
)
|
||||
for index, element in enumerate(lingo):
|
||||
if (not index % 2) and not (isinstance(element, ReencryptionCondition)):
|
||||
raise Exception(f'{index} element must be a condition; Got {type(element)}.')
|
||||
raise InvalidConditionLingo(
|
||||
f"{index} element must be a condition; Got {type(element)}."
|
||||
)
|
||||
elif (index % 2) and (not isinstance(element, Operator)):
|
||||
raise Exception(f'{index} element must be an operator; Got {type(element)}.')
|
||||
raise InvalidConditionLingo(
|
||||
f"{index} element must be an operator; Got {type(element)}."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_list(cls, payload: LingoList) -> "ConditionLingo":
|
||||
|
@ -240,7 +247,9 @@ class ConditionLingo:
|
|||
elif isinstance(task, Operator):
|
||||
yield task
|
||||
else:
|
||||
raise TypeError(f"Unrecognized type {type(task)} for ConditionLingo")
|
||||
raise InvalidConditionLingo(
|
||||
f"Unrecognized type {type(task)} for ConditionLingo"
|
||||
)
|
||||
|
||||
def eval(self, *args, **kwargs) -> bool:
|
||||
data = self.__process(*args, **kwargs)
|
||||
|
|
|
@ -11,6 +11,7 @@ from nucypher.policy.conditions.exceptions import (
|
|||
ConditionEvaluationFailed,
|
||||
ContextVariableVerificationFailed,
|
||||
InvalidCondition,
|
||||
InvalidConditionLingo,
|
||||
InvalidContextVariableData,
|
||||
NoConnectionToChain,
|
||||
RequiredContextVariable,
|
||||
|
@ -84,7 +85,9 @@ def resolve_condition_lingo(
|
|||
elif operator:
|
||||
return Operator
|
||||
else:
|
||||
raise Exception(f"Cannot resolve condition lingo type from data {data}")
|
||||
raise InvalidConditionLingo(
|
||||
f"Cannot resolve condition lingo type from data {data}"
|
||||
)
|
||||
|
||||
|
||||
def deserialize_condition_lingo(
|
||||
|
@ -134,6 +137,11 @@ def evaluate_condition_lingo(
|
|||
f"Unable to evaluate return value: {e}",
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
)
|
||||
except InvalidConditionLingo as e:
|
||||
error = (
|
||||
f"Invalid condition grammar: {e}",
|
||||
HTTPStatus.BAD_REQUEST,
|
||||
)
|
||||
except InvalidCondition as e:
|
||||
error = (
|
||||
f"Incorrect value provided for condition: {e}",
|
||||
|
|
|
@ -3,6 +3,7 @@ import pytest
|
|||
import nucypher
|
||||
from nucypher.blockchain.eth.constants import NULL_ADDRESS
|
||||
from nucypher.policy.conditions.context import USER_ADDRESS_CONTEXT
|
||||
from nucypher.policy.conditions.exceptions import InvalidConditionLingo
|
||||
from nucypher.policy.conditions.lingo import ConditionLingo
|
||||
|
||||
|
||||
|
@ -16,10 +17,10 @@ def lingo():
|
|||
|
||||
|
||||
def test_invalid_condition():
|
||||
with pytest.raises(Exception):
|
||||
with pytest.raises(InvalidConditionLingo):
|
||||
ConditionLingo.from_list([{}])
|
||||
|
||||
with pytest.raises(Exception):
|
||||
with pytest.raises(InvalidConditionLingo):
|
||||
ConditionLingo.from_list([{"dont_mind_me": "nothing_to_see_here"}])
|
||||
|
||||
|
||||
|
|
|
@ -29,11 +29,13 @@ from nucypher.policy.conditions.utils import (
|
|||
camel_case_to_snake,
|
||||
evaluate_condition_lingo,
|
||||
to_camelcase,
|
||||
validate_condition_lingo,
|
||||
)
|
||||
|
||||
FAILURE_CASE_EXCEPTION_CODE_MATCHING = [
|
||||
# (exception, constructor parameters, expected status code)
|
||||
(ReturnValueEvaluationError, None, HTTPStatus.BAD_REQUEST),
|
||||
(InvalidConditionLingo, None, HTTPStatus.BAD_REQUEST),
|
||||
(InvalidCondition, None, HTTPStatus.BAD_REQUEST),
|
||||
(RequiredContextVariable, None, HTTPStatus.BAD_REQUEST),
|
||||
(InvalidContextVariableData, None, HTTPStatus.BAD_REQUEST),
|
||||
|
@ -124,3 +126,25 @@ def test_camel_case_schema():
|
|||
|
||||
reloaded_function = schema.load(output)
|
||||
assert reloaded_function == {"field_name_with_underscores": f"{value}"}
|
||||
|
||||
|
||||
def test_condition_lingo_validation(compound_lingo):
|
||||
# valid compound lingo
|
||||
compound_lingo_list = compound_lingo.to_list()
|
||||
validate_condition_lingo(compound_lingo_list)
|
||||
|
||||
# no issues here
|
||||
invalid_operator_lingo = [
|
||||
{"returnValueTest": {"value": 0, "comparator": ">"}, "method": "timelock"},
|
||||
{"operator": "AND_OPERATOR"}, # replace operator with invalid one
|
||||
{
|
||||
"returnValueTest": {"value": 99999999999999999, "comparator": "<"},
|
||||
"method": "timelock",
|
||||
},
|
||||
]
|
||||
with pytest.raises(InvalidLogicalOperator):
|
||||
validate_condition_lingo(invalid_operator_lingo)
|
||||
|
||||
# invalid condition
|
||||
with pytest.raises(InvalidConditionLingo):
|
||||
validate_condition_lingo([{"dont_mind_me": "nothing_to_see_here"}])
|
||||
|
|
Loading…
Reference in New Issue