"""Source mapping: the parts that work without a network.""" from __future__ import annotations from datetime import date from app.settings_schema import JiraSourceSettings, LaundrySourceSettings from app.sources.jira import JiraSource, start_date_clause from app.sources.laundry import parse_cookie_header, parse_my_slots JIRA_CONFIG = JiraSourceSettings( enabled=True, base_url="https://example.atlassian.net", email="me@example.com", api_token="token", ) def test_start_date_clause_handles_custom_fields_and_names(): assert start_date_clause("customfield_10015") == "cf[10015]" assert start_date_clause("Start date") == '"Start date"' def test_jira_jql_includes_the_extra_filter(): source = JiraSource(JIRA_CONFIG.model_copy(update={"extra_jql": "assignee = currentUser()"})) jql = source._jql() assert "statusCategory != Done" in jql assert "assignee = currentUser()" in jql source.close() def test_jira_issue_maps_to_a_todo_item(): source = JiraSource(JIRA_CONFIG) item = source._to_item( { "key": "ABC-1", "fields": { "summary": "Fix the thing", "duedate": "2026-10-20", "customfield_10015": "2026-10-15", "status": {"name": "In Progress", "statusCategory": {"key": "indeterminate"}}, "priority": {"name": "High"}, "project": {"name": "Platform"}, "labels": ["backend"], }, } ) source.close() assert item.external_id == "ABC-1" assert item.title == "Fix the thing" assert item.url == "https://example.atlassian.net/browse/ABC-1" assert item.due_date == date(2026, 10, 20) assert item.start_date == date(2026, 10, 15) assert item.priority == "High" assert item.is_done is False assert item.days_overdue(date(2026, 10, 22)) == 2 def test_cookie_header_accepts_both_forms(): assert parse_cookie_header("abc123") == {"sessionid": "abc123"} parsed = parse_cookie_header("csrftoken=x; sessionid=abc123") assert parsed["sessionid"] == "abc123" LAUNDRY_HTML = """
Этаж 1
Машинка 3
09:00-12:00
18:00-21:00
21:00-00:00
""" def test_laundry_grid_yields_only_my_upcoming_slots(): label, slots = parse_my_slots(LAUNDRY_HTML) assert label == "Чт, 15 окт." assert len(slots) == 2 upcoming = [slot for slot in slots if slot.is_upcoming] assert len(upcoming) == 1 assert upcoming[0].time_range == "18:00-21:00" assert upcoming[0].machine == "Машинка 3" assert upcoming[0].location == "Этаж 1" def test_laundry_config_requires_a_session_cookie(): from app.sources.base import SourceError try: from app.sources.laundry import LaundrySource LaundrySource(LaundrySourceSettings(enabled=True, session_cookie="")) except SourceError: return raise AssertionError("expected a SourceError")