From e2e1cbd5ba1d7a5843839e97201d305da3a3fe17 Mon Sep 17 00:00:00 2001 From: Michael Wikberg Date: Tue, 15 Mar 2022 20:13:17 +0200 Subject: [PATCH] Fix tests --- tests/vw_timer_test.py | 33 +++++++++++++++++++++++++++++---- tests/vw_vehicle_test.py | 14 ++++++++------ volkswagencarnet/vw_timer.py | 16 +++++++++++++--- 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/tests/vw_timer_test.py b/tests/vw_timer_test.py index 8b321cad..fcbba5e9 100644 --- a/tests/vw_timer_test.py +++ b/tests/vw_timer_test.py @@ -1,7 +1,8 @@ """Depature timer tests.""" +import datetime from unittest import TestCase -from volkswagencarnet.vw_timer import TimerData, TimerProfile +from volkswagencarnet.vw_timer import TimerData, TimerProfile, parse_vw_datetime class TimerTest(TestCase): @@ -13,7 +14,7 @@ class TimerTest(TestCase): "timerProfileList": { "timerProfile": [ { - "timestamp": "2022-02-22T20:00:22Z", + "timestamp": "2022-02-22T20:00:22+0000", "profileName": "Profile 1", "profileID": "1", "operationCharging": True, @@ -30,7 +31,7 @@ class TimerTest(TestCase): "timerList": { "timer": [ { - "timestamp": "2022-02-22T20:00:22Z", + "timestamp": "2022-02-22T20:00:22+0000", # actual data probably has "Z", but either works "timerID": "3", "profileID": "3", "timerProgrammedStatus": "notProgrammed", @@ -42,7 +43,7 @@ class TimerTest(TestCase): ] }, "timerBasicSetting": { - "timestamp": "2022-02-22T20:00:22Z", + "timestamp": "2022-02-22T20:00:22+0000", "chargeMinLimit": 20, "targetTemperature": 2955, "heaterSource": None, @@ -97,6 +98,7 @@ def test_timer_serialization(self): """Test de- and serialization of timers.""" timer = TimerData(**self.data["timer"]) self.assertEqual(self.data, timer.json) + self.assertTrue(timer.valid) self.assertNotEqual(timer.json, timer.json_updated) def test_update_serialization(self): @@ -133,3 +135,26 @@ def test_update_profile(self): profile.profileID = 42 self.assertRaises(Exception, timer.update_profile(profile)) + + def test_parse_datetime(self): + """Test that we can parse datetimes.""" + self.assertEqual(parse_vw_datetime("2021-03-04 05:06:07Z"), None) + self.assertEqual(parse_vw_datetime("2021-03-04T05:06:07"), None) + self.assertEqual( + parse_vw_datetime("2021-03-04T05:06:07Z"), + datetime.datetime( + year=2021, month=3, day=4, hour=5, minute=6, second=7, microsecond=0, tzinfo=datetime.timezone.utc + ), + ) + self.assertEqual( + parse_vw_datetime("2021-03-04T05:06:07+0000"), + datetime.datetime( + year=2021, month=3, day=4, hour=5, minute=6, second=7, microsecond=0, tzinfo=datetime.timezone.utc + ), + ) + self.assertEqual( + parse_vw_datetime("2021-03-04T05:06:07+00:00"), + datetime.datetime( + year=2021, month=3, day=4, hour=5, minute=6, second=7, microsecond=0, tzinfo=datetime.timezone.utc + ), + ) diff --git a/tests/vw_vehicle_test.py b/tests/vw_vehicle_test.py index 3fb87898..67d68ff3 100644 --- a/tests/vw_vehicle_test.py +++ b/tests/vw_vehicle_test.py @@ -1,9 +1,8 @@ """Vehicle class tests.""" -from datetime import datetime +from datetime import datetime, timezone import pytest import sys -from dateutil.tz import UTC from volkswagencarnet.vw_timer import TimerData from volkswagencarnet.vw_utilities import json_loads @@ -195,7 +194,8 @@ async def test_get_schedule2(self): with patch.dict(vehicle._services, {"timerprogramming_v1": {"active": True}}): await vehicle.get_timerprogramming() self.assertFalse(vehicle.is_departure_timer2_supported) - self.assertIsNone(vehicle.departure_timer2) + with self.assertRaises(ValueError): + self.assertIsNone(vehicle.departure_timer2) async def test_get_schedule1(self): """Test that schedule 1 support works.""" @@ -205,7 +205,8 @@ async def test_get_schedule1(self): with patch.dict(vehicle._services, {"timerprogramming_v1": {"active": True}}): await vehicle.get_timerprogramming() self.assertFalse(vehicle.is_departure_timer1_supported) - self.assertIsNone(vehicle.departure_timer1) + with self.assertRaises(ValueError): + self.assertIsNone(vehicle.departure_timer1) async def test_get_schedule_not_supported(self): """Test that not found schedule is unsupported.""" @@ -215,7 +216,8 @@ async def test_get_schedule_not_supported(self): with patch.dict(vehicle._services, {"timerprogramming_v1": {"active": True}}): await vehicle.get_timerprogramming() self.assertFalse(vehicle.is_schedule_supported(42)) - self.assertIsNone(vehicle.schedule(42)) + with self.assertRaises(ValueError): + self.assertIsNone(vehicle.schedule(42)) async def test_get_schedule_last_updated(self): """Test that not found schedule is unsupported.""" @@ -224,7 +226,7 @@ async def test_get_schedule_last_updated(self): with patch.dict(vehicle._services, {"timerprogramming_v1": {"active": True}}): await vehicle.get_timerprogramming() - dt = datetime.fromisoformat("2022-02-22T20:00:22+00:00").astimezone(UTC) + dt = datetime.fromisoformat("2022-02-22T20:00:22+00:00").astimezone(timezone.utc) self.assertEqual(dt, vehicle.schedule_heater_source_last_updated) self.assertEqual(dt, vehicle.schedule_min_charge_level_last_updated) self.assertEqual(dt, vehicle.departure_timer3_last_updated) diff --git a/volkswagencarnet/vw_timer.py b/volkswagencarnet/vw_timer.py index d8355a2b..1e9f4541 100644 --- a/volkswagencarnet/vw_timer.py +++ b/volkswagencarnet/vw_timer.py @@ -61,10 +61,20 @@ def serialize(self, o): } for k, v in res.items(): if isinstance(v, datetime): - res["k"] = v.strftime("%Y-%m-%dT%H:%M:%S%z") + res[k] = v.strftime("%Y-%m-%dT%H:%M:%S%z") return res +def parse_vw_datetime(timestamp: str): + """Parse a VW backend datetime string to datetime.""" + try: + return datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S%z") + except (TypeError, ValueError): + """The value was not a date.""" + _LOGGER.warning(f"Failed to parse {timestamp} as datetime") + return None + + # noinspection PyPep8Naming class BasicSettings(DepartureTimerClass): """ @@ -81,7 +91,7 @@ def __init__( heaterSource: Optional[str] = None, ): """Init.""" - self.timestamp: datetime = timestamp if isinstance(timestamp, datetime) else datetime.fromisoformat(timestamp) + self.timestamp: datetime = timestamp if isinstance(timestamp, datetime) else parse_vw_datetime(timestamp) self.chargeMinLimit: Optional[int] = int(chargeMinLimit) if chargeMinLimit is not None else None self.targetTemperature: Optional[int] = int(targetTemperature) if targetTemperature is not None else None self.heaterSource: Optional[str] = heaterSource @@ -145,7 +155,7 @@ def __init__( **kw, ): """Init.""" - self.timestamp: datetime = timestamp if isinstance(timestamp, datetime) else datetime.fromisoformat(timestamp) + self.timestamp: datetime = timestamp if isinstance(timestamp, datetime) else parse_vw_datetime(timestamp) self.timerID = timerID self.profileID = profileID self.timerProgrammedStatus = timerProgrammedStatus