"""Tests for agenda.add_new_conference.""" from datetime import date, datetime import typing import lxml.html # type: ignore[import-untyped] import pytest import yaml from agenda import add_new_conference def test_parse_osm_url_mlat_mlon() -> None: """OpenStreetMap URLs with mlat/mlon should parse.""" result = add_new_conference.parse_osm_url( "https://www.openstreetmap.org/?mlat=51.5&mlon=-0.12" ) assert result == (51.5, -0.12) def test_extract_google_maps_latlon_at_pattern() -> None: """Google Maps @lat,lon URLs should parse.""" result = add_new_conference.extract_google_maps_latlon( "https://www.google.com/maps/place/Venue/@51.5242464,-0.0997024,17z/" ) assert result == (51.5242464, -0.0997024) def test_insert_sorted_allows_same_url_different_year_without_year_component() -> None: """The same non-year-specific URL can be reused for a different year.""" conferences: list[dict[str, typing.Any]] = [ { "name": "OldConf", "start": date(2025, 6, 1), "url": "https://example.com/conf", } ] new_conf: dict[str, typing.Any] = { "name": "NewConf", "start": date(2026, 6, 1), "url": "https://example.com/conf", } updated = add_new_conference.insert_sorted(conferences, new_conf) assert len(updated) == 2 assert updated[1]["name"] == "NewConf" def test_validate_country_normalises_name() -> None: """Country names should be normalised to alpha-2 codes.""" conf: dict[str, typing.Any] = {"country": "United Kingdom"} add_new_conference.validate_country(conf) assert conf["country"] == "gb" def test_normalise_end_field_defaults_single_day_date() -> None: """Non-Geomob conferences should default end to the start date.""" conf: dict[str, typing.Any] = { "name": "PyCon", "start": date(2026, 4, 10), } add_new_conference.normalise_end_field(conf, "plain text") assert conf["end"] == date(2026, 4, 10) def test_normalise_end_field_sets_geomob_end_time() -> None: """Geomob conferences should default to a 22:00 end time.""" conf: dict[str, typing.Any] = { "name": "Geomob London", "start": date(2026, 1, 28), "url": "https://thegeomob.com/post/jan-28th-2026-geomoblon-details", } add_new_conference.normalise_end_field(conf, "see you there") assert conf["end"] == datetime(2026, 1, 28, 22, 0) def test_detect_page_coordinates_uses_first_supported_link() -> None: """Page coordinate detection should inspect anchor hrefs.""" root = lxml.html.fromstring( ( "
" 'Example' 'Map' "" ) ) assert add_new_conference.detect_page_coordinates(root) == (51.5, -0.12) def test_add_new_conference_updates_yaml( tmp_path: typing.Any, monkeypatch: pytest.MonkeyPatch ) -> None: """The end-to-end import flow should append a generated conference.""" yaml_path = tmp_path / "conferences.yaml" yaml_path.write_text( yaml.dump( [ { "name": "ExistingConf", "start": date(2026, 4, 1), "end": date(2026, 4, 2), "url": "https://example.com/existing", } ], sort_keys=False, ) ) root = lxml.html.fromstring( ( "" 'Map' "" ) ) monkeypatch.setattr(add_new_conference, "fetch_webpage", lambda url: root) monkeypatch.setattr( add_new_conference, "webpage_to_text", lambda parsed: "Conference details", ) monkeypatch.setattr( add_new_conference, "get_from_open_ai", lambda prompt: { "yaml": yaml.dump( { "name": "NewConf", "topic": "Tech", "location": "New York", "country": "United States", "start": date(2026, 5, 3), "url": "https://example.com/newconf", }, sort_keys=False, ) }, ) added = add_new_conference.add_new_conference( "https://example.com/newconf", str(yaml_path) ) assert added is True written = yaml.safe_load(yaml_path.read_text()) assert len(written) == 2 assert written[1]["name"] == "NewConf" assert written[1]["country"] == "us" assert written[1]["end"] == date(2026, 5, 3) assert written[1]["latitude"] == 40.0 assert written[1]["longitude"] == -74.0