"""Tests for calendar platform of local calendar.""" import datetime import textwrap import pytest from homeassistant.const import STATE_OFF, STATE_ON from homeassistant.core import HomeAssistant from homeassistant.helpers.template import DATE_STR_FORMAT import homeassistant.util.dt as dt_util from .conftest import ( FRIENDLY_NAME, TEST_ENTITY, ClientFixture, GetEventsFn, event_fields, ) from tests.common import MockConfigEntry async def test_empty_calendar( hass: HomeAssistant, setup_integration: None, get_events: GetEventsFn ) -> None: """Test querying the API and fetching events.""" events = await get_events("1997-07-14T00:00:00", "1997-07-16T00:00:00") assert len(events) == 0 state = hass.states.get(TEST_ENTITY) assert state assert state.name == FRIENDLY_NAME assert state.state == STATE_OFF assert dict(state.attributes) == { "friendly_name": FRIENDLY_NAME, "supported_features": 7, } @pytest.mark.parametrize( ("dtstart", "dtend"), [ ("1997-07-14T18:00:00+01:00", "1997-07-15T05:00:00+01:00"), ("1997-07-14T17:00:00+00:00", "1997-07-15T04:00:00+00:00"), ("1997-07-14T11:00:00-06:00", "1997-07-14T22:00:00-06:00"), ("1997-07-14T10:00:00-07:00", "1997-07-14T21:00:00-07:00"), ], ) async def test_api_date_time_event( ws_client: ClientFixture, setup_integration: None, get_events: GetEventsFn, dtstart: str, dtend: str, ) -> None: """Test an event with a start/end date time. Events created in various timezones are ultimately returned relative to local home assistant timezone. """ client = await ws_client() await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Bastille Day Party", "dtstart": dtstart, "dtend": dtend, }, }, ) events = await get_events("1997-07-14T00:00:00Z", "1997-07-16T00:00:00Z") assert list(map(event_fields, events)) == [ { "summary": "Bastille Day Party", "start": {"dateTime": "1997-07-14T11:00:00-06:00"}, "end": {"dateTime": "1997-07-14T22:00:00-06:00"}, } ] # Query events in UTC # Time range before event events = await get_events("1997-07-13T00:00:00Z", "1997-07-14T16:00:00Z") assert len(events) == 0 # Time range after event events = await get_events("1997-07-15T05:00:00Z", "1997-07-15T06:00:00Z") assert len(events) == 0 # Overlap with event start events = await get_events("1997-07-13T00:00:00Z", "1997-07-14T18:00:00Z") assert len(events) == 1 # Overlap with event end events = await get_events("1997-07-15T03:00:00Z", "1997-07-15T06:00:00Z") assert len(events) == 1 # Query events overlapping with start and end but in another timezone events = await get_events("1997-07-12T23:00:00-01:00", "1997-07-14T17:00:00-01:00") assert len(events) == 1 events = await get_events("1997-07-15T02:00:00-01:00", "1997-07-15T05:00:00-01:00") assert len(events) == 1 async def test_api_date_event( ws_client: ClientFixture, setup_integration: None, get_events: GetEventsFn ) -> None: """Test an event with a start/end date all day event.""" client = await ws_client() await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Festival International de Jazz de Montreal", "dtstart": "2007-06-28", "dtend": "2007-07-09", }, }, ) events = await get_events("2007-06-20T00:00:00", "2007-07-20T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Festival International de Jazz de Montreal", "start": {"date": "2007-06-28"}, "end": {"date": "2007-07-09"}, } ] # Time range before event (timezone is -6) events = await get_events("2007-06-26T00:00:00Z", "2007-06-28T01:00:00Z") assert len(events) == 0 # Time range after event events = await get_events("2007-07-10T00:00:00Z", "2007-07-11T00:00:00Z") assert len(events) == 0 # Overlap with event start (timezone is -6) events = await get_events("2007-06-26T00:00:00Z", "2007-06-28T08:00:00Z") assert len(events) == 1 # Overlap with event end events = await get_events("2007-07-09T00:00:00Z", "2007-07-11T00:00:00Z") assert len(events) == 1 async def test_active_event( hass: HomeAssistant, ws_client: ClientFixture, setup_integration: None, ) -> None: """Test an event with a start/end date time.""" start = dt_util.now() - datetime.timedelta(minutes=30) end = dt_util.now() + datetime.timedelta(minutes=30) client = await ws_client() await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Evening lights", "dtstart": start.isoformat(), "dtend": end.isoformat(), }, }, ) state = hass.states.get(TEST_ENTITY) assert state assert state.name == FRIENDLY_NAME assert state.state == STATE_ON assert dict(state.attributes) == { "friendly_name": FRIENDLY_NAME, "message": "Evening lights", "all_day": False, "description": "", "location": "", "start_time": start.strftime(DATE_STR_FORMAT), "end_time": end.strftime(DATE_STR_FORMAT), "supported_features": 7, } async def test_upcoming_event( hass: HomeAssistant, ws_client: ClientFixture, setup_integration: None, ) -> None: """Test an event with a start/end date time.""" start = dt_util.now() + datetime.timedelta(days=1) end = dt_util.now() + datetime.timedelta(days=1, hours=1) client = await ws_client() await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Evening lights", "dtstart": start.isoformat(), "dtend": end.isoformat(), }, }, ) state = hass.states.get(TEST_ENTITY) assert state assert state.name == FRIENDLY_NAME assert state.state == STATE_OFF assert dict(state.attributes) == { "friendly_name": FRIENDLY_NAME, "message": "Evening lights", "all_day": False, "description": "", "location": "", "start_time": start.strftime(DATE_STR_FORMAT), "end_time": end.strftime(DATE_STR_FORMAT), "supported_features": 7, } async def test_recurring_event( ws_client: ClientFixture, setup_integration: None, hass: HomeAssistant, get_events: GetEventsFn, ) -> None: """Test an event with a recurrence rule.""" client = await ws_client() await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Monday meeting", "dtstart": "2022-08-29T09:00:00", "dtend": "2022-08-29T10:00:00", "rrule": "FREQ=WEEKLY", }, }, ) events = await get_events("2022-08-20T00:00:00", "2022-09-20T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Monday meeting", "start": {"dateTime": "2022-08-29T09:00:00-06:00"}, "end": {"dateTime": "2022-08-29T10:00:00-06:00"}, "recurrence_id": "20220829T090000", }, { "summary": "Monday meeting", "start": {"dateTime": "2022-09-05T09:00:00-06:00"}, "end": {"dateTime": "2022-09-05T10:00:00-06:00"}, "recurrence_id": "20220905T090000", }, { "summary": "Monday meeting", "start": {"dateTime": "2022-09-12T09:00:00-06:00"}, "end": {"dateTime": "2022-09-12T10:00:00-06:00"}, "recurrence_id": "20220912T090000", }, { "summary": "Monday meeting", "start": {"dateTime": "2022-09-19T09:00:00-06:00"}, "end": {"dateTime": "2022-09-19T10:00:00-06:00"}, "recurrence_id": "20220919T090000", }, ] async def test_websocket_delete( ws_client: ClientFixture, setup_integration: None, get_events: GetEventsFn ) -> None: """Test websocket delete command.""" client = await ws_client() await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Bastille Day Party", "dtstart": "1997-07-14T17:00:00+00:00", "dtend": "1997-07-15T04:00:00+00:00", }, }, ) events = await get_events("1997-07-14T00:00:00", "1997-07-16T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Bastille Day Party", "start": {"dateTime": "1997-07-14T11:00:00-06:00"}, "end": {"dateTime": "1997-07-14T22:00:00-06:00"}, } ] uid = events[0]["uid"] # Delete the event await client.cmd_result( "delete", { "entity_id": TEST_ENTITY, "uid": uid, }, ) events = await get_events("1997-07-14T00:00:00", "1997-07-16T00:00:00") assert list(map(event_fields, events)) == [] async def test_websocket_delete_recurring( ws_client: ClientFixture, setup_integration: None, get_events: GetEventsFn ) -> None: """Test deleting a recurring event.""" client = await ws_client() await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Morning Routine", "dtstart": "2022-08-22T08:30:00", "dtend": "2022-08-22T09:00:00", "rrule": "FREQ=DAILY", }, }, ) events = await get_events("2022-08-22T00:00:00", "2022-08-26T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Morning Routine", "start": {"dateTime": "2022-08-22T08:30:00-06:00"}, "end": {"dateTime": "2022-08-22T09:00:00-06:00"}, "recurrence_id": "20220822T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-23T08:30:00-06:00"}, "end": {"dateTime": "2022-08-23T09:00:00-06:00"}, "recurrence_id": "20220823T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-24T08:30:00-06:00"}, "end": {"dateTime": "2022-08-24T09:00:00-06:00"}, "recurrence_id": "20220824T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-25T08:30:00-06:00"}, "end": {"dateTime": "2022-08-25T09:00:00-06:00"}, "recurrence_id": "20220825T083000", }, ] uid = events[0]["uid"] assert [event["uid"] for event in events] == [uid] * 4 # Cancel a single instance and confirm it was removed await client.cmd_result( "delete", { "entity_id": TEST_ENTITY, "uid": uid, "recurrence_id": "20220824T083000", }, ) events = await get_events("2022-08-22T00:00:00", "2022-08-26T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Morning Routine", "start": {"dateTime": "2022-08-22T08:30:00-06:00"}, "end": {"dateTime": "2022-08-22T09:00:00-06:00"}, "recurrence_id": "20220822T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-23T08:30:00-06:00"}, "end": {"dateTime": "2022-08-23T09:00:00-06:00"}, "recurrence_id": "20220823T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-25T08:30:00-06:00"}, "end": {"dateTime": "2022-08-25T09:00:00-06:00"}, "recurrence_id": "20220825T083000", }, ] # Delete all and future and confirm multiple were removed await client.cmd_result( "delete", { "entity_id": TEST_ENTITY, "uid": uid, "recurrence_id": "20220823T083000", "recurrence_range": "THISANDFUTURE", }, ) events = await get_events("2022-08-22T00:00:00", "2022-08-26T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Morning Routine", "start": {"dateTime": "2022-08-22T08:30:00-06:00"}, "end": {"dateTime": "2022-08-22T09:00:00-06:00"}, "recurrence_id": "20220822T083000", }, ] async def test_websocket_update( ws_client: ClientFixture, setup_integration: None, get_events: GetEventsFn ) -> None: """Test websocket update command.""" client = await ws_client() await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Bastille Day Party", "dtstart": "1997-07-14T17:00:00+00:00", "dtend": "1997-07-15T04:00:00+00:00", }, }, ) events = await get_events("1997-07-14T00:00:00", "1997-07-16T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Bastille Day Party", "start": {"dateTime": "1997-07-14T11:00:00-06:00"}, "end": {"dateTime": "1997-07-14T22:00:00-06:00"}, } ] uid = events[0]["uid"] # Update the event await client.cmd_result( "update", { "entity_id": TEST_ENTITY, "uid": uid, "event": { "summary": "Bastille Day Party [To be rescheduled]", "dtstart": "1997-07-14", "dtend": "1997-07-15", }, }, ) events = await get_events("1997-07-14T00:00:00", "1997-07-16T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Bastille Day Party [To be rescheduled]", "start": {"date": "1997-07-14"}, "end": {"date": "1997-07-15"}, } ] async def test_websocket_update_recurring_this_and_future( ws_client: ClientFixture, setup_integration: None, get_events: GetEventsFn ) -> None: """Test updating a recurring event.""" client = await ws_client() await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Morning Routine", "dtstart": "2022-08-22T08:30:00", "dtend": "2022-08-22T09:00:00", "rrule": "FREQ=DAILY", }, }, ) events = await get_events("2022-08-22T00:00:00", "2022-08-26T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Morning Routine", "start": {"dateTime": "2022-08-22T08:30:00-06:00"}, "end": {"dateTime": "2022-08-22T09:00:00-06:00"}, "recurrence_id": "20220822T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-23T08:30:00-06:00"}, "end": {"dateTime": "2022-08-23T09:00:00-06:00"}, "recurrence_id": "20220823T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-24T08:30:00-06:00"}, "end": {"dateTime": "2022-08-24T09:00:00-06:00"}, "recurrence_id": "20220824T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-25T08:30:00-06:00"}, "end": {"dateTime": "2022-08-25T09:00:00-06:00"}, "recurrence_id": "20220825T083000", }, ] uid = events[0]["uid"] assert [event["uid"] for event in events] == [uid] * 4 # Update a single instance and confirm the change is reflected await client.cmd_result( "update", { "entity_id": TEST_ENTITY, "uid": uid, "recurrence_id": "20220824T083000", "recurrence_range": "THISANDFUTURE", "event": { "summary": "Morning Routine [Adjusted]", "dtstart": "2022-08-24T08:00:00", "dtend": "2022-08-24T08:30:00", }, }, ) events = await get_events("2022-08-22T00:00:00", "2022-08-26T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Morning Routine", "start": {"dateTime": "2022-08-22T08:30:00-06:00"}, "end": {"dateTime": "2022-08-22T09:00:00-06:00"}, "recurrence_id": "20220822T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-23T08:30:00-06:00"}, "end": {"dateTime": "2022-08-23T09:00:00-06:00"}, "recurrence_id": "20220823T083000", }, { "summary": "Morning Routine [Adjusted]", "start": {"dateTime": "2022-08-24T08:00:00-06:00"}, "end": {"dateTime": "2022-08-24T08:30:00-06:00"}, "recurrence_id": "20220824T080000", }, { "summary": "Morning Routine [Adjusted]", "start": {"dateTime": "2022-08-25T08:00:00-06:00"}, "end": {"dateTime": "2022-08-25T08:30:00-06:00"}, "recurrence_id": "20220825T080000", }, ] async def test_websocket_update_recurring( ws_client: ClientFixture, setup_integration: None, get_events: GetEventsFn ) -> None: """Test updating a recurring event.""" client = await ws_client() await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Morning Routine", "dtstart": "2022-08-22T08:30:00", "dtend": "2022-08-22T09:00:00", "rrule": "FREQ=DAILY", }, }, ) events = await get_events("2022-08-22T00:00:00", "2022-08-26T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Morning Routine", "start": {"dateTime": "2022-08-22T08:30:00-06:00"}, "end": {"dateTime": "2022-08-22T09:00:00-06:00"}, "recurrence_id": "20220822T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-23T08:30:00-06:00"}, "end": {"dateTime": "2022-08-23T09:00:00-06:00"}, "recurrence_id": "20220823T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-24T08:30:00-06:00"}, "end": {"dateTime": "2022-08-24T09:00:00-06:00"}, "recurrence_id": "20220824T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-25T08:30:00-06:00"}, "end": {"dateTime": "2022-08-25T09:00:00-06:00"}, "recurrence_id": "20220825T083000", }, ] uid = events[0]["uid"] assert [event["uid"] for event in events] == [uid] * 4 # Update a single instance and confirm the change is reflected await client.cmd_result( "update", { "entity_id": TEST_ENTITY, "uid": uid, "recurrence_id": "20220824T083000", "event": { "summary": "Morning Routine [Adjusted]", "dtstart": "2022-08-24T08:00:00", "dtend": "2022-08-24T08:30:00", }, }, ) events = await get_events("2022-08-22T00:00:00", "2022-08-26T00:00:00") assert list(map(event_fields, events)) == [ { "summary": "Morning Routine", "start": {"dateTime": "2022-08-22T08:30:00-06:00"}, "end": {"dateTime": "2022-08-22T09:00:00-06:00"}, "recurrence_id": "20220822T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-23T08:30:00-06:00"}, "end": {"dateTime": "2022-08-23T09:00:00-06:00"}, "recurrence_id": "20220823T083000", }, { "summary": "Morning Routine [Adjusted]", "start": {"dateTime": "2022-08-24T08:00:00-06:00"}, "end": {"dateTime": "2022-08-24T08:30:00-06:00"}, "recurrence_id": "20220824T083000", }, { "summary": "Morning Routine", "start": {"dateTime": "2022-08-25T08:30:00-06:00"}, "end": {"dateTime": "2022-08-25T09:00:00-06:00"}, "recurrence_id": "20220825T083000", }, ] @pytest.mark.parametrize( "rrule", [ "FREQ=SECONDLY", "FREQ=MINUTELY", "FREQ=HOURLY", "invalid", "", ], ) async def test_invalid_rrule( ws_client: ClientFixture, setup_integration: None, hass: HomeAssistant, get_events: GetEventsFn, rrule: str, ) -> None: """Test an event with a recurrence rule.""" client = await ws_client() resp = await client.cmd( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Monday meeting", "dtstart": "2022-08-29T09:00:00", "dtend": "2022-08-29T10:00:00", "rrule": rrule, }, }, ) assert resp assert not resp.get("success") assert "error" in resp assert resp["error"].get("code") == "invalid_format" @pytest.mark.parametrize( ("time_zone", "event_order"), [ ("America/Los_Angeles", ["One", "Two", "All Day Event"]), ("America/Regina", ["One", "Two", "All Day Event"]), ("UTC", ["One", "All Day Event", "Two"]), ("Asia/Tokyo", ["All Day Event", "One", "Two"]), ], ) async def test_all_day_iter_order( hass: HomeAssistant, ws_client: ClientFixture, setup_integration: None, get_events: GetEventsFn, event_order: list[str], ): """Test the sort order of an all day events depending on the time zone.""" client = await ws_client() await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "All Day Event", "dtstart": "2022-10-08", "dtend": "2022-10-09", }, }, ) await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "One", "dtstart": "2022-10-07T23:00:00+00:00", "dtend": "2022-10-07T23:30:00+00:00", }, }, ) await client.cmd_result( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Two", "dtstart": "2022-10-08T01:00:00+00:00", "dtend": "2022-10-08T02:00:00+00:00", }, }, ) events = await get_events("2022-10-06T00:00:00Z", "2022-10-09T00:00:00Z") assert [event["summary"] for event in events] == event_order async def test_start_end_types( ws_client: ClientFixture, setup_integration: None, ) -> None: """Test a start and end with different date and date time types.""" client = await ws_client() result = await client.cmd( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Bastille Day Party", "dtstart": "1997-07-15", "dtend": "1997-07-14T17:00:00+00:00", }, }, ) assert result assert not result.get("success") assert "error" in result assert "code" in result["error"] assert result["error"]["code"] == "invalid_format" async def test_end_before_start( ws_client: ClientFixture, setup_integration: None, ) -> None: """Test an event with a start/end date time.""" client = await ws_client() result = await client.cmd( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Bastille Day Party", "dtstart": "1997-07-15T04:00:00+00:00", "dtend": "1997-07-14T17:00:00+00:00", }, }, ) assert result assert not result.get("success") assert "error" in result assert "code" in result["error"] assert result["error"]["code"] == "invalid_format" async def test_invalid_recurrence_rule( ws_client: ClientFixture, setup_integration: None, ) -> None: """Test an event with a recurrence rule.""" client = await ws_client() result = await client.cmd( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Monday meeting", "dtstart": "2022-08-29T09:00:00", "dtend": "2022-08-29T10:00:00", "rrule": "FREQ=invalid;'", }, }, ) assert result assert not result.get("success") assert "error" in result assert "code" in result["error"] assert result["error"]["code"] == "invalid_format" async def test_invalid_date_formats( ws_client: ClientFixture, setup_integration: None, get_events: GetEventsFn ) -> None: """Exercises a validation error within rfc5545 parsing in ical.""" client = await ws_client() result = await client.cmd( "create", { "entity_id": TEST_ENTITY, "event": { "summary": "Bastille Day Party", # Can't mix offset aware and floating dates "dtstart": "1997-07-15T04:00:00+08:00", "dtend": "1997-07-14T17:00:00", }, }, ) assert result assert not result.get("success") assert "error" in result assert "code" in result["error"] assert result["error"]["code"] == "invalid_format" async def test_update_invalid_event_id( ws_client: ClientFixture, setup_integration: None, hass: HomeAssistant, ) -> None: """Test updating an event with an invalid event uid.""" client = await ws_client() resp = await client.cmd( "update", { "entity_id": TEST_ENTITY, "uid": "uid-does-not-exist", "event": { "summary": "Bastille Day Party [To be rescheduled]", "dtstart": "1997-07-14", "dtend": "1997-07-15", }, }, ) assert resp assert not resp.get("success") assert "error" in resp assert resp["error"].get("code") == "failed" async def test_delete_invalid_event_id( ws_client: ClientFixture, setup_integration: None, hass: HomeAssistant, ) -> None: """Test deleting an event with an invalid event uid.""" client = await ws_client() resp = await client.cmd( "delete", { "entity_id": TEST_ENTITY, "uid": "uid-does-not-exist", }, ) assert resp assert not resp.get("success") assert "error" in resp assert resp["error"].get("code") == "failed" @pytest.mark.parametrize( ("start_date_time", "end_date_time"), [ ("1997-07-14T17:00:00+00:00", "1997-07-15T04:00:00+00:00"), ("1997-07-14T11:00:00-06:00", "1997-07-14T22:00:00-06:00"), ], ) async def test_create_event_service( hass: HomeAssistant, setup_integration: None, get_events: GetEventsFn, start_date_time: str, end_date_time: str, config_entry: MockConfigEntry, ) -> None: """Test creating an event using the create_event service.""" await hass.services.async_call( "calendar", "create_event", { "start_date_time": start_date_time, "end_date_time": end_date_time, "summary": "Bastille Day Party", "location": "Test Location", }, target={"entity_id": TEST_ENTITY}, blocking=True, ) # Ensure data is written to disk await hass.async_block_till_done() events = await get_events("1997-07-14T00:00:00Z", "1997-07-16T00:00:00Z") assert list(map(event_fields, events)) == [ { "summary": "Bastille Day Party", "start": {"dateTime": "1997-07-14T11:00:00-06:00"}, "end": {"dateTime": "1997-07-14T22:00:00-06:00"}, "location": "Test Location", } ] events = await get_events("1997-07-13T00:00:00Z", "1997-07-14T18:00:00Z") assert list(map(event_fields, events)) == [ { "summary": "Bastille Day Party", "start": {"dateTime": "1997-07-14T11:00:00-06:00"}, "end": {"dateTime": "1997-07-14T22:00:00-06:00"}, "location": "Test Location", } ] # Reload the config entry, which reloads the content from the store and # verifies that the persisted data can be parsed correctly. await hass.config_entries.async_reload(config_entry.entry_id) await hass.async_block_till_done() events = await get_events("1997-07-13T00:00:00Z", "1997-07-14T18:00:00Z") assert list(map(event_fields, events)) == [ { "summary": "Bastille Day Party", "start": {"dateTime": "1997-07-14T11:00:00-06:00"}, "end": {"dateTime": "1997-07-14T22:00:00-06:00"}, "location": "Test Location", } ] @pytest.mark.parametrize( "ics_content", [ textwrap.dedent( """\ BEGIN:VCALENDAR BEGIN:VEVENT SUMMARY:Bastille Day Party DTSTART:19970714 DTEND:19970714 END:VEVENT END:VCALENDAR """ ), textwrap.dedent( """\ BEGIN:VCALENDAR BEGIN:VEVENT SUMMARY:Bastille Day Party DTSTART:19970714 DTEND:19970710 END:VEVENT END:VCALENDAR """ ), ], ids=["no_duration", "negative"], ) async def test_invalid_all_day_event( ws_client: ClientFixture, setup_integration: None, get_events: GetEventsFn, ) -> None: """Test all day events with invalid durations, which are coerced to be valid.""" events = await get_events("1997-07-14T00:00:00Z", "1997-07-16T00:00:00Z") assert list(map(event_fields, events)) == [ { "summary": "Bastille Day Party", "start": {"date": "1997-07-14"}, "end": {"date": "1997-07-15"}, } ] @pytest.mark.parametrize( "ics_content", [ textwrap.dedent( """\ BEGIN:VCALENDAR BEGIN:VEVENT SUMMARY:Bastille Day Party DTSTART:19970714T110000 DTEND:19970714T110000 END:VEVENT END:VCALENDAR """ ), textwrap.dedent( """\ BEGIN:VCALENDAR BEGIN:VEVENT SUMMARY:Bastille Day Party DTSTART:19970714T110000 DTEND:19970710T100000 END:VEVENT END:VCALENDAR """ ), ], ids=["no_duration", "negative"], ) async def test_invalid_event_duration( ws_client: ClientFixture, setup_integration: None, get_events: GetEventsFn, ) -> None: """Test events with invalid durations, which are coerced to be valid.""" events = await get_events("1997-07-14T00:00:00Z", "1997-07-16T00:00:00Z") assert list(map(event_fields, events)) == [ { "summary": "Bastille Day Party", "start": {"dateTime": "1997-07-14T11:00:00-06:00"}, "end": {"dateTime": "1997-07-14T11:30:00-06:00"}, } ]