Skip to content

Commit

Permalink
fix: date validation forbids legal values (DEV-3059) (#668)
Browse files Browse the repository at this point in the history
  • Loading branch information
jnussbaum committed Dec 5, 2023
1 parent 5b333c2 commit 13131ff
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 17 deletions.
8 changes: 2 additions & 6 deletions src/dsp_tools/commands/excel2xml/excel2xml_lib.py
Expand Up @@ -18,6 +18,7 @@
from dsp_tools.commands.excel2xml.propertyelement import PropertyElement
from dsp_tools.models.exceptions import BaseError
from dsp_tools.models.helpers import DateTimeStamp
from dsp_tools.utils.date_util import is_full_date
from dsp_tools.utils.shared import check_notna, simplify_name, validate_xml_against_schema
from dsp_tools.utils.uri_util import is_uri

Expand Down Expand Up @@ -660,13 +661,8 @@ def make_date_prop(
values = prepare_value(value)

# check value type
validation_regex = (
r"^(GREGORIAN:|JULIAN:)?(CE:|BCE:)?"
+ r"(\d{4})(-\d{1,2})?(-\d{1,2})?"
+ r"((:CE|:BCE)?(:\d{4})(-\d{1,2})?(-\d{1,2})?)?$"
)
for val in values:
if not regex.search(validation_regex, str(val.value).strip()):
if not is_full_date(str(val.value).strip()):
raise BaseError(
f"Failed validation in resource '{calling_resource}', property '{name}': "
f"'{val.value}' is not a valid DSP date."
Expand Down
2 changes: 1 addition & 1 deletion src/dsp_tools/resources/schema/data.xsd
Expand Up @@ -31,7 +31,7 @@
<xs:simpleType name="knoradate_type">
<xs:restriction base="xs:token">
<xs:pattern
value="(GREGORIAN:|JULIAN:)?(CE:|BCE:)?(\d{4})(-\d{1,2})?(-\d{1,2})?((:CE|:BCE)?(:\d{4})(-\d{1,2})?(-\d{1,2})?)?"/>
value="(GREGORIAN:|JULIAN:|ISLAMIC:)?(CE:|BCE:|AD:|BC:)?(\d{1,4})(-\d{1,2})?(-\d{1,2})?((:CE|:BCE|:AD|:BC)?(:\d{1,4})(-\d{1,2})?(-\d{1,2})?)?"/>
</xs:restriction>
</xs:simpleType>

Expand Down
26 changes: 19 additions & 7 deletions src/dsp_tools/utils/date_util.py
Expand Up @@ -8,16 +8,21 @@

from dsp_tools.models.exceptions import BaseError

_full_date_pattern = r"""
_calendar = r"GREGORIAN|JULIAN|ISLAMIC"
_era = r"CE|BCE|BC|AD"
_year = r"\d{1,4}"
_month = r"\d{1,2}"
_day = r"\d{1,2}"
_full_date_pattern = rf"""
^
(?:(GREGORIAN|JULIAN|ISLAMIC):)? # optional calendar
(?:(CE|BCE|BC|AD):)? # optional era
(\d{1,4}(?:-\d{1,2})?(?:-\d{1,2})?) # date
(?::(CE|BCE|BC|AD))? # optional era
(?::(\d{4}(?:-\d{1,2})?(?:-\d{1,2})?))? # optional date
(?:({_calendar}):)? # optional calendar
(?:({_era}):)? # optional era
({_year}(?:-{_month})?(?:-{_day})?) # date
(?::({_era}))? # optional era
(?::({_year}(?:-{_month})?(?:-{_day})?))? # optional date
$
"""
_single_date_pattern = r"^(\d{1,4})(?:-(\d{1,2}))?(?:-(\d{1,2}))?$"
_single_date_pattern = rf"^({_year})(?:-({_month}))?(?:-({_day}))?$"


class Calendar(Enum):
Expand Down Expand Up @@ -114,6 +119,13 @@ def parse_date_string(s: str) -> Date:
return Date(calendar_enum, start, end)


def is_full_date(s: str) -> bool:
"""
Check if a string is a full DSP date string of the scheme calendar:epoch:yyyy-mm-dd:epoch:yyyy-mm-dd.
"""
return bool(regex.search(_full_date_pattern, s, flags=regex.VERBOSE))


def _split_date_string(s: str) -> tuple[str | None, str | None, str, str | None, str | None]:
date_match = regex.search(_full_date_pattern, s, flags=regex.VERBOSE)
if not date_match:
Expand Down
3 changes: 2 additions & 1 deletion test/unittests/commands/excel2xml/test_excel2xml_lib.py
Expand Up @@ -396,8 +396,9 @@ def test_make_date_prop(self) -> None:
"2022",
"GREGORIAN:CE:0476-09-04:CE:0476-09-04",
"GREGORIAN:CE:2014-01-31",
"JULIAN:BC:1:AD:200",
]
invalid_values = ["GREGORIAN:CE:0476-09-04:CE:09-04", "GREGORIAN:CE:0476-09-010:CE:0476-09-04"]
invalid_values = ["GREGORIAN:CE:0476-09-010:CE:0476-09-04"]
run_test(self, prop, method, different_values, invalid_values)

def test_make_decimal_prop(self) -> None:
Expand Down
5 changes: 3 additions & 2 deletions testdata/xml-data/test-data-systematic.xml
Expand Up @@ -110,12 +110,13 @@
<boolean permissions="prop-default">true</boolean>
</boolean-prop>
<date-prop name=":hasDate">
<date permissions="prop-default">JULIAN:BCE:0700:BCE:0600</date>
<date permissions="prop-default">JULIAN:BCE:70:CE:1</date>
<date permissions="prop-default">CE:1849:CE:1850</date>
<date permissions="prop-default">GREGORIAN:1848-01:1849-02</date>
<date permissions="prop-default">2022</date>
<date permissions="prop-default">GREGORIAN:CE:0476-09-04:CE:0476-09-04</date>
<date permissions="prop-default">GREGORIAN:AD:0476-09-04:AD:0476-09-04</date>
<date permissions="prop-default">GREGORIAN:CE:2014-01-31</date>
<date permissions="prop-default">ISLAMIC:1:100</date>
</date-prop>
<integer-prop name=":hasInteger">
<integer permissions="prop-default">4711</integer>
Expand Down

0 comments on commit 13131ff

Please sign in to comment.