"""Tests for agenda.airbnb module.""" import pytest from datetime import datetime from zoneinfo import ZoneInfo from unittest.mock import Mock, patch, mock_open from agenda.airbnb import ( build_datetime, list_to_dict, extract_country_code, walk_tree, get_ui_state, get_reservation_data, get_price_from_reservation, parse_multiple_files, ) class TestBuildDatetime: def test_build_datetime_utc(self): result = build_datetime("2025-07-28", "15:30", "UTC") expected = datetime(2025, 7, 28, 15, 30, tzinfo=ZoneInfo("UTC")) assert result == expected def test_build_datetime_local_timezone(self): result = build_datetime("2025-12-25", "09:00", "Europe/London") expected = datetime(2025, 12, 25, 9, 0, tzinfo=ZoneInfo("Europe/London")) assert result == expected class TestListToDict: def test_list_to_dict_even_items(self): items = ["key1", "value1", "key2", "value2"] result = list_to_dict(items) expected = {"key1": "value1", "key2": "value2"} assert result == expected def test_list_to_dict_empty_list(self): result = list_to_dict([]) assert result == {} def test_list_to_dict_single_pair(self): items = ["name", "John"] result = list_to_dict(items) assert result == {"name": "John"} class TestExtractCountryCode: def test_extract_country_code_uk(self): address = "123 Main Street, London, United Kingdom" result = extract_country_code(address) assert result == "gb" def test_extract_country_code_france(self): address = "456 Rue de la Paix, Paris, France" result = extract_country_code(address) assert result == "fr" def test_extract_country_code_usa(self): address = "789 Broadway, New York, United States" result = extract_country_code(address) assert result == "us" def test_extract_country_code_not_found(self): address = "123 Unknown Street, Mystery City" result = extract_country_code(address) assert result is None def test_extract_country_code_case_insensitive(self): address = "123 Main Street, UNITED KINGDOM" result = extract_country_code(address) assert result == "gb" class TestWalkTree: def test_walk_tree_dict_found(self): data = {"level1": {"level2": {"target": "found"}}} result = walk_tree(data, "target") assert result == "found" def test_walk_tree_dict_not_found(self): data = {"level1": {"level2": {"other": "value"}}} result = walk_tree(data, "target") assert result is None def test_walk_tree_list_found(self): data = [{"other": "value"}, {"target": "found"}] result = walk_tree(data, "target") assert result == "found" def test_walk_tree_nested_list_dict(self): data = [{"level1": [{"target": "found"}]}] result = walk_tree(data, "target") assert result == "found" def test_walk_tree_empty_data(self): result = walk_tree({}, "target") assert result is None class TestGetPriceFromReservation: def test_get_price_from_reservation_valid(self): reservation = { "payment_summary": {"subtitle": "Total cost: £150.00"} } result = get_price_from_reservation(reservation) assert result == "150.00" def test_get_price_from_reservation_different_amount(self): reservation = { "payment_summary": {"subtitle": "Total cost: £89.99"} } result = get_price_from_reservation(reservation) assert result == "89.99" class TestParseMultipleFiles: @patch('agenda.airbnb.extract_booking_from_html') def test_parse_multiple_files_single_file(self, mock_extract): mock_booking = { "type": "apartment", "operator": "airbnb", "name": "Test Apartment", "booking_reference": "ABC123" } mock_extract.return_value = mock_booking result = parse_multiple_files(["test1.html"]) assert len(result) == 1 assert result[0] == mock_booking mock_extract.assert_called_once_with("test1.html") @patch('agenda.airbnb.extract_booking_from_html') def test_parse_multiple_files_multiple_files(self, mock_extract): mock_booking1 = {"booking_reference": "ABC123"} mock_booking2 = {"booking_reference": "DEF456"} mock_extract.side_effect = [mock_booking1, mock_booking2] result = parse_multiple_files(["test2.html", "test1.html"]) assert len(result) == 2 assert result[0] == mock_booking1 assert result[1] == mock_booking2 @patch('agenda.airbnb.extract_booking_from_html') def test_parse_multiple_files_empty_list(self, mock_extract): result = parse_multiple_files([]) assert result == [] mock_extract.assert_not_called() class TestGetUiState: @patch('lxml.html.etree') def test_get_ui_state_with_mock_tree(self, mock_etree): mock_tree = Mock() mock_tree.xpath.return_value = ['{"test": [["uiState", {"key": "value"}]]}'] with patch('agenda.airbnb.walk_tree') as mock_walk: mock_walk.return_value = [["key", "value"]] result = get_ui_state(mock_tree) assert result == {"key": "value"} mock_tree.xpath.assert_called_once_with('//*[@id="data-injector-instances"]/text()') class TestGetReservationData: def test_get_reservation_data(self): ui_state = { "reservation": { "scheduled_event": { "rows": [ {"id": "row1", "data": "value1"}, {"id": "row2", "data": "value2"} ] } } } result = get_reservation_data(ui_state) expected = { "row1": {"id": "row1", "data": "value1"}, "row2": {"id": "row2", "data": "value2"} } assert result == expected