209 lines
7.4 KiB
Python
209 lines
7.4 KiB
Python
"""Tests for agenda.gwr module."""
|
|
|
|
import os
|
|
import tempfile
|
|
from datetime import date
|
|
from typing import Any
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
import pytest
|
|
|
|
from agenda.gwr import (
|
|
advance_ticket_date,
|
|
advance_tickets_page_html,
|
|
extract_dates,
|
|
extract_weekday_date,
|
|
parse_date_string,
|
|
)
|
|
|
|
|
|
class TestParseDateString:
|
|
"""Tests for parse_date_string function."""
|
|
|
|
def test_parse_date_with_year(self) -> None:
|
|
"""Test parsing date string with year included."""
|
|
result = parse_date_string("Monday 25 December 2023")
|
|
assert result == date(2023, 12, 25)
|
|
|
|
def test_parse_date_without_year(self) -> None:
|
|
"""Test parsing date string without year (should use current year)."""
|
|
current_year = date.today().year
|
|
result = parse_date_string("Monday 25 December")
|
|
assert result == date(current_year, 12, 25)
|
|
|
|
def test_parse_different_formats(self) -> None:
|
|
"""Test parsing various date formats."""
|
|
result = parse_date_string("Friday 1 January 2024")
|
|
assert result == date(2024, 1, 1)
|
|
|
|
result = parse_date_string("Saturday 29 February 2024")
|
|
assert result == date(2024, 2, 29)
|
|
|
|
|
|
class TestExtractDates:
|
|
"""Tests for extract_dates function."""
|
|
|
|
def test_extract_valid_dates(self) -> None:
|
|
"""Test extracting dates from valid HTML."""
|
|
html = """
|
|
<tr><td>Weekdays</td><td>Monday 25 December 2023</td></tr>
|
|
<tr><td>Saturdays</td><td>Saturday 23 December 2023</td></tr>
|
|
<tr><td>Sundays</td><td>Sunday 24 December 2023</td></tr>
|
|
"""
|
|
result = extract_dates(html)
|
|
expected = {
|
|
"Weekdays": date(2023, 12, 25),
|
|
"Saturdays": date(2023, 12, 23),
|
|
"Sundays": date(2023, 12, 24),
|
|
}
|
|
assert result == expected
|
|
|
|
def test_extract_dates_with_asterisks(self) -> None:
|
|
"""Test extracting dates when HTML contains asterisks."""
|
|
html = """
|
|
<tr><td>Weekdays</td><td>Monday 25 December 2023**</td></tr>
|
|
"""
|
|
result = extract_dates(html)
|
|
expected = {"Weekdays": date(2023, 12, 25)}
|
|
assert result == expected
|
|
|
|
def test_extract_dates_no_match(self) -> None:
|
|
"""Test extracting dates when no pattern matches."""
|
|
html = "<p>No relevant table data here</p>"
|
|
result = extract_dates(html)
|
|
assert result is None
|
|
|
|
def test_extract_dates_whitespace_handling(self) -> None:
|
|
"""Test extracting dates with various whitespace."""
|
|
html = """
|
|
<tr> <td>Weekdays</td> <td>Monday 25 December 2023</td> </tr>
|
|
"""
|
|
result = extract_dates(html)
|
|
expected = {"Weekdays": date(2023, 12, 25)}
|
|
assert result == expected
|
|
|
|
|
|
class TestExtractWeekdayDate:
|
|
"""Tests for extract_weekday_date function."""
|
|
|
|
def test_extract_valid_weekday_date(self) -> None:
|
|
"""Test extracting weekday date from valid HTML."""
|
|
html = """
|
|
<tr><td>Weekdays</td><td>Monday 25 December 2023</td></tr>
|
|
"""
|
|
result = extract_weekday_date(html)
|
|
assert result == date(2023, 12, 25)
|
|
|
|
def test_extract_weekday_date_with_asterisks(self) -> None:
|
|
"""Test extracting weekday date when HTML contains asterisks."""
|
|
html = """
|
|
<tr><td>Weekdays</td><td>Monday 25 December 2023**</td></tr>
|
|
"""
|
|
result = extract_weekday_date(html)
|
|
assert result == date(2023, 12, 25)
|
|
|
|
def test_extract_weekday_date_no_match(self) -> None:
|
|
"""Test extracting weekday date when no pattern matches."""
|
|
html = "<p>No weekday data here</p>"
|
|
result = extract_weekday_date(html)
|
|
assert result is None
|
|
|
|
def test_extract_weekday_date_multiline(self) -> None:
|
|
"""Test extracting weekday date with multiline content."""
|
|
html = """
|
|
<tr>
|
|
<td>Weekdays</td>
|
|
<td>Monday 25 December 2023</td>
|
|
</tr>
|
|
"""
|
|
result = extract_weekday_date(html)
|
|
assert result == date(2023, 12, 25)
|
|
|
|
|
|
class TestAdvanceTicketsPageHtml:
|
|
"""Tests for advance_tickets_page_html function."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_cache_hit(self) -> None:
|
|
"""Test using cached HTML when file is fresh."""
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
cache_file = os.path.join(temp_dir, "advance-tickets.html")
|
|
test_content = "<html>test content</html>"
|
|
|
|
# Create a fresh cache file
|
|
with open(cache_file, "w") as f:
|
|
f.write(test_content)
|
|
|
|
result = await advance_tickets_page_html(temp_dir, ttl=3600)
|
|
assert result == test_content
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_force_cache(self) -> None:
|
|
"""Test forcing cache usage even when file doesn't exist."""
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
cache_file = os.path.join(temp_dir, "advance-tickets.html")
|
|
test_content = "<html>cached content</html>"
|
|
|
|
with open(cache_file, "w") as f:
|
|
f.write(test_content)
|
|
|
|
result = await advance_tickets_page_html(temp_dir, force_cache=True)
|
|
assert result == test_content
|
|
|
|
@pytest.mark.asyncio
|
|
@patch("httpx.AsyncClient")
|
|
async def test_fetch_from_web(self, mock_client: Any) -> None:
|
|
"""Test fetching from web when cache is stale."""
|
|
mock_response = AsyncMock()
|
|
mock_response.text = "<html>fresh content</html>"
|
|
mock_client.return_value.__aenter__.return_value.get.return_value = (
|
|
mock_response
|
|
)
|
|
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
result = await advance_tickets_page_html(temp_dir, ttl=0)
|
|
assert result == "<html>fresh content</html>"
|
|
|
|
# Check that content was cached
|
|
cache_file = os.path.join(temp_dir, "advance-tickets.html")
|
|
with open(cache_file) as f:
|
|
cached_content = f.read()
|
|
assert cached_content == "<html>fresh content</html>"
|
|
|
|
|
|
class TestAdvanceTicketDate:
|
|
"""Tests for advance_ticket_date function."""
|
|
|
|
@pytest.mark.asyncio
|
|
@patch("agenda.gwr.advance_tickets_page_html")
|
|
async def test_advance_ticket_date_success(self, mock_html: Any) -> None:
|
|
"""Test successfully extracting advance ticket date."""
|
|
mock_html.return_value = """
|
|
<tr><td>Weekdays</td><td>Monday 25 December 2023</td></tr>
|
|
"""
|
|
|
|
result = await advance_ticket_date("/fake/dir")
|
|
assert result == date(2023, 12, 25)
|
|
mock_html.assert_called_once_with("/fake/dir", force_cache=False)
|
|
|
|
@pytest.mark.asyncio
|
|
@patch("agenda.gwr.advance_tickets_page_html")
|
|
async def test_advance_ticket_date_no_match(self, mock_html: Any) -> None:
|
|
"""Test when no weekday date can be extracted."""
|
|
mock_html.return_value = "<p>No relevant data</p>"
|
|
|
|
result = await advance_ticket_date("/fake/dir")
|
|
assert result is None
|
|
|
|
@pytest.mark.asyncio
|
|
@patch("agenda.gwr.advance_tickets_page_html")
|
|
async def test_advance_ticket_date_force_cache(self, mock_html: Any) -> None:
|
|
"""Test advance_ticket_date with force_cache parameter."""
|
|
mock_html.return_value = """
|
|
<tr><td>Weekdays</td><td>Tuesday 26 December 2023</td></tr>
|
|
"""
|
|
|
|
result = await advance_ticket_date("/fake/dir", force_cache=True)
|
|
assert result == date(2023, 12, 26)
|
|
mock_html.assert_called_once_with("/fake/dir", force_cache=True)
|