62 lines
2.1 KiB
Python
62 lines
2.1 KiB
Python
from datetime import datetime
|
||
from zoneinfo import ZoneInfo
|
||
|
||
import pytest
|
||
|
||
from app.crawler import _parse_date, _parse_date_range, _weekly_dates, external_key, ExtractedEvent
|
||
|
||
|
||
NOW = datetime(2026, 9, 7, 12, 0, tzinfo=ZoneInfo("Australia/Sydney"))
|
||
SOURCE = {"timezone": "Australia/Sydney", "date_format": ""}
|
||
|
||
|
||
def test_parses_naive_australian_date_with_timezone():
|
||
value = _parse_date("7 September 2026 7:30pm", SOURCE, NOW)
|
||
assert value.isoformat() == "2026-09-07T19:30:00+10:00"
|
||
|
||
|
||
def test_parses_explicit_format_without_year_to_next_occurrence():
|
||
value = _parse_date("4 Sep 19:30", {**SOURCE, "date_format": "%d %b %H:%M"}, NOW)
|
||
assert value.year == 2027
|
||
|
||
|
||
@pytest.mark.parametrize("separator", ["-", "–", "—"])
|
||
def test_same_month_range(separator):
|
||
start, end = _parse_date_range(f"2 {separator} 13 Sep 2026", SOURCE, NOW)
|
||
assert (start.year, start.month, start.day) == (2026, 9, 2)
|
||
assert (end.year, end.month, end.day) == (2026, 9, 13)
|
||
|
||
|
||
def test_cross_month_range():
|
||
start, end = _parse_date_range("30 Sep - 4 Oct 2026", SOURCE, NOW)
|
||
assert (start.month, start.day) == (9, 30)
|
||
assert (end.month, end.day) == (10, 4)
|
||
|
||
|
||
def test_non_range_has_no_end():
|
||
start, end = _parse_date_range("9 September 2026 8pm", SOURCE, NOW)
|
||
assert start.hour == 20
|
||
assert end is None
|
||
|
||
|
||
def test_rejects_relative_only_and_implausible_dates():
|
||
with pytest.raises(ValueError):
|
||
_parse_date("next Friday", SOURCE, NOW)
|
||
with pytest.raises(ValueError):
|
||
_parse_date("13 Sep 2002", SOURCE, NOW)
|
||
|
||
|
||
def test_weekly_dates_generate_twelve_occurrences():
|
||
values = _weekly_dates("Every Friday", NOW)
|
||
assert len(values) == 12
|
||
assert values[0].weekday() == 4
|
||
assert all((right - left).days == 7 for left, right in zip(values, values[1:]))
|
||
|
||
|
||
def test_external_key_is_case_insensitive_but_time_sensitive():
|
||
first = ExtractedEvent("Trivia", NOW, address="Town Hall")
|
||
same = ExtractedEvent("TRIVIA", NOW, address="TOWN HALL")
|
||
later = ExtractedEvent("Trivia", NOW.replace(hour=13), address="Town Hall")
|
||
assert external_key(first) == external_key(same)
|
||
assert external_key(first) != external_key(later)
|