# Path: augur/util_support/date_disambiguator.py
# def tuple_to_date(year, month, day):
# def max_day_for_year_month(year, month):
# def resolve_uncertain_int(uncertain_string, min_or_max):
#     def __init__(self, uncertain_date, fmt="%Y-%m-%d", min_max_year=None):
#     def range(self):
#     def uncertain_date_components(self):
#     def fmt_components(self):
#     def regex(self):
#     def assert_only_less_significant_uncertainty(self):
# class DateDisambiguator:
# 
# Path: augur/util_support/date_disambiguator.py
# class DateDisambiguator:
#     """Transforms a date string with uncertainty into the range of possible dates."""
# 
#     def __init__(self, uncertain_date, fmt="%Y-%m-%d", min_max_year=None):
#         self.uncertain_date = uncertain_date
#         self.fmt = fmt
#         self.min_max_year = min_max_year
# 
#         self.assert_only_less_significant_uncertainty()
# 
#     def range(self):
#         min_date = tuple_to_date(
#             resolve_uncertain_int(self.uncertain_date_components["Y"], "min"),
#             resolve_uncertain_int(self.uncertain_date_components["m"], "min"),
#             resolve_uncertain_int(self.uncertain_date_components["d"], "min"),
#         )
# 
#         max_date = tuple_to_date(
#             resolve_uncertain_int(self.uncertain_date_components["Y"], "max"),
#             resolve_uncertain_int(self.uncertain_date_components["m"], "max"),
#             resolve_uncertain_int(self.uncertain_date_components["d"], "max"),
#         )
#         max_date = min(max_date, datetime.date.today())
# 
#         return (min_date, max_date)
# 
#     @property
#     @functools.lru_cache()
#     def uncertain_date_components(self):
#         matches = re.search(self.regex, self.uncertain_date)
# 
#         if matches is None:
#             raise ValueError(
#                 f"Malformed uncertain date `{self.uncertain_date}` for format `{self.fmt}`"
#             )
# 
#         return dict(zip(self.fmt_components, matches.groups()))
# 
#     @property
#     @functools.lru_cache()
#     def fmt_components(self):
#         # The `re` module doesn't capture repeated groups, so we'll do it without regexes
#         return [component[0] for component in self.fmt.split("%") if len(component) > 0]
# 
#     @property
#     def regex(self):
#         """
#         Returns regex defined by the format string.
#         Currently only supports %Y, %m, and %d.
#         """
#         return re.compile(
#             "^"
#             + self.fmt.replace("%Y", "(....)")
#             .replace("%m", "(..?)")
#             .replace("%d", "(..?)")
#             + "$"
#         )
# 
#     def assert_only_less_significant_uncertainty(self):
#         """
#         Raise an exception if a constrained digit appears in a less-significant place
#         than an uncertain digit.
# 
#         Assuming %Y-%m-%d, these patterns are valid:
#             2000-01-01
#             2000-01-XX
#             2000-XX-XX
# 
#         but this is invalid, because month is uncertain but day is constrained:
#             2000-XX-01
# 
#         These invalid cases are assumed to be unintended use of the tool.
#         """
#         if "X" in self.uncertain_date_components["Y"]:
#             if (
#                 self.uncertain_date_components["m"] != "XX"
#                 or self.uncertain_date_components["d"] != "XX"
#             ):
#                 raise ValueError(
#                     "Invalid date: Year contains uncertainty, so month and day must also be uncertain."
#                 )
#         elif "X" in self.uncertain_date_components["m"]:
#             if self.uncertain_date_components["d"] != "XX":
#                 raise ValueError(
#                     "Invalid date: Month contains uncertainty, so day must also be uncertain."
#                 )


import datetime
import pytest
from augur.util_support import date_disambiguator
from augur.util_support.date_disambiguator import DateDisambiguator
from freezegun import freeze_time
    def test_uncertain_date_components_error(self):
        with pytest.raises(ValueError, match="Malformed uncertain date"):
            DateDisambiguator("5-5-5-5-5").uncertain_date_components

    @pytest.mark.parametrize(
        "date_str, min_or_max, expected",
        [
            ("2000", "min", 2000),
            ("2000", "max", 2000),
            ("200X", "min", 2000),
            ("200X", "max", 2009),
            ("20X0", "max", 2090),
            ("X000", "max", 9000),
            ("XXXX", "min", 1),
            ("XXXX", "max", 9999),
        ],
    )
    def test_resolve_uncertain_int(self, date_str, min_or_max, expected):
        assert (
            date_disambiguator.resolve_uncertain_int(date_str, min_or_max) == expected
        )

    @pytest.mark.parametrize(
        "date_str, expected_error",
        [
            ("200X-01-01", "so month and day must also be uncertain"),
            ("2000-XX-01", "so day must also be uncertain"),
        ],
    )
    def test_assert_only_less_significant_uncertainty(self, date_str, expected_error):

# Path: augur/util_support/date_disambiguator.py
# def tuple_to_date(year, month, day):
# def max_day_for_year_month(year, month):
# def resolve_uncertain_int(uncertain_string, min_or_max):
#     def __init__(self, uncertain_date, fmt="%Y-%m-%d", min_max_year=None):
#     def range(self):
#     def uncertain_date_components(self):
#     def fmt_components(self):
#     def regex(self):
#     def assert_only_less_significant_uncertainty(self):
# class DateDisambiguator:
# 
# Path: augur/util_support/date_disambiguator.py
# class DateDisambiguator:
#     """Transforms a date string with uncertainty into the range of possible dates."""
# 
#     def __init__(self, uncertain_date, fmt="%Y-%m-%d", min_max_year=None):
#         self.uncertain_date = uncertain_date
#         self.fmt = fmt
#         self.min_max_year = min_max_year
# 
#         self.assert_only_less_significant_uncertainty()
# 
#     def range(self):
#         min_date = tuple_to_date(
#             resolve_uncertain_int(self.uncertain_date_components["Y"], "min"),
#             resolve_uncertain_int(self.uncertain_date_components["m"], "min"),
#             resolve_uncertain_int(self.uncertain_date_components["d"], "min"),
#         )
# 
#         max_date = tuple_to_date(
#             resolve_uncertain_int(self.uncertain_date_components["Y"], "max"),
#             resolve_uncertain_int(self.uncertain_date_components["m"], "max"),
#             resolve_uncertain_int(self.uncertain_date_components["d"], "max"),
#         )
#         max_date = min(max_date, datetime.date.today())
# 
#         return (min_date, max_date)
# 
#     @property
#     @functools.lru_cache()
#     def uncertain_date_components(self):
#         matches = re.search(self.regex, self.uncertain_date)
# 
#         if matches is None:
#             raise ValueError(
#                 f"Malformed uncertain date `{self.uncertain_date}` for format `{self.fmt}`"
#             )
# 
#         return dict(zip(self.fmt_components, matches.groups()))
# 
#     @property
#     @functools.lru_cache()
#     def fmt_components(self):
#         # The `re` module doesn't capture repeated groups, so we'll do it without regexes
#         return [component[0] for component in self.fmt.split("%") if len(component) > 0]
# 
#     @property
#     def regex(self):
#         """
#         Returns regex defined by the format string.
#         Currently only supports %Y, %m, and %d.
#         """
#         return re.compile(
#             "^"
#             + self.fmt.replace("%Y", "(....)")
#             .replace("%m", "(..?)")
#             .replace("%d", "(..?)")
#             + "$"
#         )
# 
#     def assert_only_less_significant_uncertainty(self):
#         """
#         Raise an exception if a constrained digit appears in a less-significant place
#         than an uncertain digit.
# 
#         Assuming %Y-%m-%d, these patterns are valid:
#             2000-01-01
#             2000-01-XX
#             2000-XX-XX
# 
#         but this is invalid, because month is uncertain but day is constrained:
#             2000-XX-01
# 
#         These invalid cases are assumed to be unintended use of the tool.
#         """
#         if "X" in self.uncertain_date_components["Y"]:
#             if (
#                 self.uncertain_date_components["m"] != "XX"
#                 or self.uncertain_date_components["d"] != "XX"
#             ):
#                 raise ValueError(
#                     "Invalid date: Year contains uncertainty, so month and day must also be uncertain."
#                 )
#         elif "X" in self.uncertain_date_components["m"]:
#             if self.uncertain_date_components["d"] != "XX":
#                 raise ValueError(
#                     "Invalid date: Month contains uncertainty, so day must also be uncertain."
#                 )


# Path: tests/util_support/test_date_disambiguator.py
import datetime
import pytest
from augur.util_support import date_disambiguator
from augur.util_support.date_disambiguator import DateDisambiguator
from freezegun import freeze_time

    def test_uncertain_date_components_error(self):
        with pytest.raises(ValueError, match="Malformed uncertain date"):
            DateDisambiguator("5-5-5-5-5").uncertain_date_components

    @pytest.mark.parametrize(
        "date_str, min_or_max, expected",
        [
            ("2000", "min", 2000),
            ("2000", "max", 2000),
            ("200X", "min", 2000),
            ("200X", "max", 2009),
            ("20X0", "max", 2090),
            ("X000", "max", 9000),
            ("XXXX", "min", 1),
            ("XXXX", "max", 9999),
        ],
    )
    def test_resolve_uncertain_int(self, date_str, min_or_max, expected):
        assert (
            date_disambiguator.resolve_uncertain_int(date_str, min_or_max) == expected
        )

    @pytest.mark.parametrize(
        "date_str, expected_error",
        [
            ("200X-01-01", "so month and day must also be uncertain"),
            ("2000-XX-01", "so day must also be uncertain"),
        ],
    )
    def test_assert_only_less_significant_uncertainty(self, date_str, expected_error):

        with pytest.raises(ValueError, match=expected_error):