Skip to content

Commit

Permalink
tests: dates module
Browse files Browse the repository at this point in the history
  • Loading branch information
Edward-Jackson-ONS committed Aug 20, 2024
1 parent a6d9855 commit 3608d89
Showing 1 changed file with 152 additions and 0 deletions.
152 changes: 152 additions & 0 deletions tests/test_dates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
"""Unit tests for the `dates` module."""

import datetime as dt
from unittest import mock

import pytest
from hypothesis import assume, given
from hypothesis import strategies as st

from parliai_public import dates

from .common import ST_DATES, TODAY


def check_date_list(date_list, start, end):
"""Check the properties of the date list itself."""

assert isinstance(date_list, list)
assert all(isinstance(date, dt.date) for date in date_list)
assert min(date_list) == start
assert max(date_list) == end

for i, date in enumerate(date_list[:-1]):
assert (date_list[i + 1] - date).days == 1


def check_mocked_components(
formatter, checker, start=None, end=None, window=None
):
"""Check the formatter and checker mocked objects."""

assert formatter.call_count == 2
assert formatter.call_args_list == [
mock.call(limit, "%Y-%m-%d") for limit in (start, end)
]

checker.assert_called_once_with(start, end, window)


@given(
st.tuples(ST_DATES, ST_DATES).map(sorted),
st.one_of(st.just(None), st.integers(1, 14)),
)
def test_list_dates_with_endpoints(endpoints, window):
"""
Check the date lister works for start and end points.
We also check that the end points are always used even when a window
is also provided.
"""

start, end = endpoints

with (
mock.patch("parliai_public.dates._format_date") as formatter,
mock.patch("parliai_public.dates._check_date_parameters") as checker,
):
formatter.side_effect = [start, end]
date_list = dates.list_dates(start, end, window)

check_date_list(date_list, start, end)
check_mocked_components(formatter, checker, start, end, window)


@given(ST_DATES, st.integers(1, 14))
def test_list_dates_with_look_behind(end, window):
"""Check the date lister works for looking back from an endpoint."""

with (
mock.patch("parliai_public.dates._format_date") as formatter,
mock.patch("parliai_public.dates._check_date_parameters") as checker,
):
formatter.side_effect = [None, end]
date_list = dates.list_dates(end=end, window=window)

check_date_list(date_list, end - dt.timedelta(window - 1), end)
check_mocked_components(formatter, checker, end=end, window=window)


@given(ST_DATES)
def test_list_dates_with_single_date(end):
"""Check the date lister works for a single date."""

with (
mock.patch("parliai_public.dates._format_date") as formatter,
mock.patch("parliai_public.dates._check_date_parameters") as checker,
):
formatter.side_effect = [None, end]
date_list = dates.list_dates(end=end)

check_date_list(date_list, end, end)
check_mocked_components(formatter, checker, end=end)


@given(st.one_of(st.just(None), ST_DATES))
def test_format_date_with_none_or_date(date):
"""Check the date formatter does nothing with `None` or a date."""

assert dates._format_date(date) is date


@given(st.datetimes(min_value=dt.datetime(2000, 1, 1)))
def test_format_date_with_datetime(datetime):
"""Check the date formatter works for datetime objects."""

assert dates._format_date(datetime) == datetime.date()


@given(ST_DATES, st.sampled_from(("%Y-%m-%d", "%d/%m/%Y", "%a, %d %b %Y")))
def test_format_date_with_date_string(date, form):
"""Check the date formatter works for date strings."""

assert dates._format_date(date.strftime(form), form) == date


@given(ST_DATES, st.integers(1, 14))
def test_check_date_parameters_warns_for_start_and_window(start, window):
"""Check the date parameter checker warns given start and window."""

with pytest.warns(UserWarning, match="Ignoring window"):
dates._check_date_parameters(start, TODAY, window)


@given(st.dates(min_value=TODAY + dt.timedelta(days=1)))
def test_check_date_parameters_raises_for_end_in_the_future(end):
"""Check the date parameter checker raises given a future end."""

message = "End date must not be in the future."
with pytest.raises(ValueError, match=message):
dates._check_date_parameters(None, end, None)


@given(st.dates(min_value=TODAY + dt.timedelta(days=1)))
def test_check_date_parameters_raises_for_start_in_the_future(start):
"""Check the date parameter checker raises given a future start."""

message = "Start date must not be in the future."
with pytest.raises(ValueError, match=message):
dates._check_date_parameters(start, TODAY, None)


@given(st.tuples(ST_DATES, ST_DATES).map(sorted))
def test_check_date_parameters_raises_for_start_after_end(endpoints):
"""Check the checker raises given a start later than its end."""

end, start = endpoints

assume(start != end)

message = "Start date must not be after end date."
with pytest.raises(ValueError, match=message):
dates._check_date_parameters(start, end, None)

0 comments on commit 3608d89

Please sign in to comment.