Skip to content

Commit

Permalink
Fix compare_age crash (#31)
Browse files Browse the repository at this point in the history
* Fix compare_age crash

* Update compare_age tests

* Update changelog
  • Loading branch information
hewanadun authored Dec 14, 2024
1 parent a3d4d1c commit 35ec5a3
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Documentation of release versions of `nacc-form-validator`
* Refactors the tests to be more modularized so that they're more manageable
* Refactors logic for `compare_values` by moving it to its own utility method and allows comparing to null values
* Fixes issue where `datastore` was not being set for the temp validator in `_check_subschema_valid`, causing nested conditions with previous records to not evaluate correctly
* Overrides `_validate_nullable` method to drop custom rule definitions that cannot be evaluated for null values

## 0.3.0

Expand Down
12 changes: 11 additions & 1 deletion nacc_form_validator/nacc_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,16 @@ def _validate_formatting(self, formatting: str, field: str, value: object):
self.__add_system_error(field, err_msg)
raise ValidationException(err_msg)

def _validate_nullable(self, nullable, field, value):
"""Override nullable rule to drop custom defined rules.
The rule's arguments are validated against this schema:
{'type': 'boolean'}
"""
super()._validate_nullable(nullable, field, value)
if value is None:
super()._drop_remaining_rules('compare_age')

def _validate_max(self, max_value: object, field: str, value: object):
"""Override max rule to support validations wrt current date/year.
Expand Down Expand Up @@ -1088,7 +1098,7 @@ def _validate_compare_age(self, comparison: Dict[str, Any], field: str,

try:
value = utils.convert_to_date(value)
except parser.ParserError as error:
except (ValueError, TypeError, parser.ParserError) as error:
self._error(field, ErrorDefs.DATE_CONVERSION, value, error)
return

Expand Down
72 changes: 57 additions & 15 deletions tests/test_rules_compare_age.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""
Tests the custom compare_with_date rule (_validate_compare_with_date).
"""


def test_compare_age(date_constraint, create_nacc_validator):
""" Tests compare_age, case where compare_to is another field"""
schema = {
Expand Down Expand Up @@ -32,14 +34,18 @@ def test_compare_age(date_constraint, create_nacc_validator):
nv = create_nacc_validator(schema)

# valid cases
assert nv.validate({'frmdate': '2024/02/02', 'birthmo': 6, 'birthyr': 1950, 'behage': 50})
assert nv.validate({'frmdate': '2024/02/02', 'birthmo': 2, 'birthyr': 2024, 'behage': 0})
assert nv.validate(
{'frmdate': '2024/02/02', 'birthmo': 6, 'birthyr': 1950, 'behage': 50})
assert nv.validate(
{'frmdate': '2024/02/02', 'birthmo': 2, 'birthyr': 2024, 'behage': 0})

# invalid cases
assert not nv.validate({'frmdate': '2024/02/02', 'birthmo': 1, 'birthyr': 2024, 'behage': 50})
assert not nv.validate(
{'frmdate': '2024/02/02', 'birthmo': 1, 'birthyr': 2024, 'behage': 50})
assert nv.errors == {'frmdate': [
"input value behage doesn't satisfy the condition: age at frmdate >= behage"
]}
"input value behage doesn't satisfy the condition: age at frmdate >= behage"
]}


def test_compare_age_list(date_constraint, create_nacc_validator):
""" Tests compare_age, case where compare_to is a list """
Expand Down Expand Up @@ -85,15 +91,19 @@ def test_compare_age_list(date_constraint, create_nacc_validator):
nv = create_nacc_validator(schema)

# valid cases
assert nv.validate({'frmdate': '2024/02/02', 'birthmo': 6, 'birthyr': 1950, 'behage': 50, 'cogage': 40, 'perchage': 70})
assert nv.validate({'frmdate': '2024/02/02', 'birthmo': 2, 'birthyr': 2024, 'behage': 0, 'cogage': 0, 'perchage': -2})
assert nv.validate({'frmdate': '2024/02/02', 'birthmo': 6,
'birthyr': 1950, 'behage': 50, 'cogage': 40, 'perchage': 70})
assert nv.validate({'frmdate': '2024/02/02', 'birthmo': 2,
'birthyr': 2024, 'behage': 0, 'cogage': 0, 'perchage': -2})

# invalid cases
assert not nv.validate({'frmdate': '2024/02/02', 'birthmo': 1, 'birthyr': 2024, 'behage': 50, 'cogage': 0, 'perchage': 60})
assert not nv.validate({'frmdate': '2024/02/02', 'birthmo': 1,
'birthyr': 2024, 'behage': 50, 'cogage': 0, 'perchage': 60})
assert nv.errors == {'frmdate': [
"input value perchage doesn't satisfy the condition: age at frmdate >= behage, cogage, perchage, 0",
"input value behage doesn't satisfy the condition: age at frmdate >= behage, cogage, perchage, 0"
]}
"input value perchage doesn't satisfy the condition: age at frmdate >= behage, cogage, perchage, 0",
"input value behage doesn't satisfy the condition: age at frmdate >= behage, cogage, perchage, 0"
]}


def test_compare_age_invalid_field(date_constraint, create_nacc_validator):
""" Test case where invalid age to compare is provided """
Expand All @@ -118,8 +128,11 @@ def test_compare_age_invalid_field(date_constraint, create_nacc_validator):
}

nv = create_nacc_validator(schema)
assert not nv.validate({'frmdate': '2024/02/02', 'birthyr': 2024, 'behage': "dummy_str"})
assert nv.errors == {'frmdate': ["Error in comparing behage to age at frmdate (0.08761122518822724): '<=' not supported between instances of 'float' and 'str'"]}
assert not nv.validate(
{'frmdate': '2024/02/02', 'birthyr': 2024, 'behage': "dummy_str"})
assert nv.errors == {'frmdate': [
"Error in comparing behage to age at frmdate (0.08761122518822724): '<=' not supported between instances of 'float' and 'str'"]}


def test_compare_age_invalid_base(create_nacc_validator):
""" Test case where base_date is invalid """
Expand All @@ -142,5 +155,34 @@ def test_compare_age_invalid_base(create_nacc_validator):
}

nv = create_nacc_validator(schema)
assert not nv.validate({'frmdate': 'hello world', 'birthyr': 2024, 'behage': 50})
assert nv.errors == {'frmdate': ['failed to convert value hello world to a date: Unknown string format: hello world']}
assert not nv.validate(
{'frmdate': 'hello world', 'birthyr': 2024, 'behage': 50})
assert nv.errors == {'frmdate': [
'failed to convert value hello world to a date: Unknown string format: hello world']}


def test_compare_age_null_base(create_nacc_validator):
""" Test case where base_date is null """

schema = {
"frmdate": {
"type": "string",
"required": True,
"compare_age": {
"comparator": "<=",
"birth_year": "birthyr",
"compare_to": "behage",
}
},
"birthyr": {
"type": "integer"
},
"behage": {
"type": "integer"
}
}

nv = create_nacc_validator(schema)
assert not nv.validate(
nv.cast_record({'frmdate': '', 'birthyr': 2024, 'behage': 50}))
assert nv.errors == {'frmdate': ['null value not allowed']}

0 comments on commit 35ec5a3

Please sign in to comment.