Improve testing for ConditionLingo, utils. Remove unceessary check for function_abi.

pull/3016/head
derekpierre 2022-11-15 15:27:34 -05:00
parent ceee8bd2e9
commit dc488624e8
4 changed files with 76 additions and 25 deletions

View File

@ -1,8 +1,9 @@
import json
import re
from http import HTTPStatus
from typing import Dict, NamedTuple, Optional, Tuple, Type, Union
from typing import Dict, NamedTuple, Optional, Type, Union
from marshmallow import Schema, post_dump
from web3.providers import BaseProvider
@ -33,6 +34,11 @@ def to_camelcase(s):
return next(parts) + "".join(i.title() for i in parts)
def camel_case_to_snake(data: str) -> str:
data = re.sub(r"(?<!^)(?=[A-Z])", "_", data).lower()
return data
class CamelCaseSchema(Schema):
"""Schema that uses camel-case for its external representation
and snake-case for its internal representation.

View File

@ -1,6 +1,5 @@
import re
from typing import Any, Dict, List, Optional, Tuple
from eth_typing import ChecksumAddress
@ -12,7 +11,7 @@ from web3.providers import BaseProvider
from web3.types import ABIFunction
from nucypher.policy.conditions import STANDARD_ABI_CONTRACT_TYPES, STANDARD_ABIS
from nucypher.policy.conditions._utils import CamelCaseSchema
from nucypher.policy.conditions._utils import CamelCaseSchema, camel_case_to_snake
from nucypher.policy.conditions.base import ReencryptionCondition
from nucypher.policy.conditions.context import get_context_value, is_context_variable
from nucypher.policy.conditions.exceptions import (
@ -60,17 +59,9 @@ def _resolve_abi(
except ValueError as e:
raise InvalidCondition(str(e))
if not function_abi:
raise InvalidCondition(f"No function ABI supplied for '{method}'")
return ABIFunction(function_abi)
def camel_case_to_snake(data: str) -> str:
data = re.sub(r'(?<!^)(?=[A-Z])', '_', data).lower()
return data
def _resolve_any_context_variables(
parameters: List[Any], return_value_test: ReturnValueTest, **context
):

View File

@ -1,3 +1,5 @@
import pytest
from nucypher.policy.conditions.lingo import ConditionLingo
CONDITIONS = [
@ -13,6 +15,14 @@ CONDITIONS = [
]
def test_invalid_condition():
with pytest.raises(Exception):
ConditionLingo.from_list([{}])
with pytest.raises(Exception):
ConditionLingo.from_list([{"dont_mind_me": "nothing_to_see_here"}])
def test_compound_condition_timelock():
clingo = ConditionLingo.from_list(CONDITIONS)
assert clingo.eval()

View File

@ -14,36 +14,42 @@
You should have received a copy of the GNU Affero General Public License
along with nucypher. If not, see <https://www.gnu.org/licenses/>.
"""
from dataclasses import dataclass
from http import HTTPStatus
from typing import List, Tuple, Type
from typing import List, Optional, Tuple, Type
from unittest.mock import Mock
import pytest
from marshmallow import fields
from web3.providers import BaseProvider
from nucypher.policy.conditions._utils import evaluate_conditions
from nucypher.policy.conditions._utils import (
CamelCaseSchema,
camel_case_to_snake,
evaluate_conditions,
to_camelcase,
)
from nucypher.policy.conditions.exceptions import *
FAILURE_CASE_EXCEPTION_CODE_MATCHING = [
# (exception, constructor parameters, expected status code)
(ReturnValueEvaluationError, [], HTTPStatus.BAD_REQUEST),
(InvalidCondition, [], HTTPStatus.BAD_REQUEST),
(RequiredContextVariable, [], HTTPStatus.BAD_REQUEST),
(InvalidContextVariableData, [], HTTPStatus.BAD_REQUEST),
(ContextVariableVerificationFailed, [], HTTPStatus.FORBIDDEN),
(ReturnValueEvaluationError, None, HTTPStatus.BAD_REQUEST),
(InvalidCondition, None, HTTPStatus.BAD_REQUEST),
(RequiredContextVariable, None, HTTPStatus.BAD_REQUEST),
(InvalidContextVariableData, None, HTTPStatus.BAD_REQUEST),
(ContextVariableVerificationFailed, None, HTTPStatus.FORBIDDEN),
(NoConnectionToChain, [1], HTTPStatus.NOT_IMPLEMENTED),
(ConditionEvaluationFailed, [], HTTPStatus.BAD_REQUEST),
(Exception, [], HTTPStatus.INTERNAL_SERVER_ERROR),
(ConditionEvaluationFailed, None, HTTPStatus.BAD_REQUEST),
(Exception, None, HTTPStatus.INTERNAL_SERVER_ERROR),
]
@pytest.mark.parametrize("failure_case", FAILURE_CASE_EXCEPTION_CODE_MATCHING)
def test_evaluate_condition_exception_cases(
failure_case: Tuple[Type[Exception], List, int]
failure_case: Tuple[Type[Exception], Optional[List], int]
):
exception_class = failure_case[0]
exception_constructor_params = failure_case[1]
expected_status_code = failure_case[2]
exception_class, exception_constructor_params, expected_status_code = failure_case
exception_constructor_params = exception_constructor_params or []
condition_lingo = Mock()
condition_lingo.eval.side_effect = exception_class(*exception_constructor_params)
@ -79,4 +85,42 @@ def test_evaluate_condition_eval_returns_true():
context={"key1": "value1", "key2": "value2"}, # multiple values in fake context
)
assert not eval_error
assert eval_error is None
@pytest.mark.parametrize(
"test_case",
(
("nounderscores", "nounderscores"),
("one_underscore", "oneUnderscore"),
("two_under_scores", "twoUnderScores"),
),
)
def test_to_from_camel_case(test_case: Tuple[str, str]):
# test to_camelcase()
snake_case, camel_case = test_case
result = to_camelcase(snake_case)
assert result == camel_case
# test camel_case_to_snake()
result = camel_case_to_snake(camel_case)
assert result == snake_case
def test_camel_case_schema():
# test CamelCaseSchema
@dataclass
class Function:
field_name_with_underscores: str
class FunctionSchema(CamelCaseSchema):
field_name_with_underscores = fields.Str()
value = "field_name_value"
function = Function(field_name_with_underscores=value)
schema = FunctionSchema()
output = schema.dump(function)
assert output == {"fieldNameWithUnderscores": f"{value}"}
reloaded_function = schema.load(output)
assert reloaded_function == {"field_name_with_underscores": f"{value}"}