async def test_get_schedule3(self):
        """Test that schedule 3 support works."""
        vehicle = Vehicle(conn=TimersConnection(None), url=MOCK_VIN)
        vehicle._discovered = True

        with patch.dict(vehicle._services,
                        {"timerprogramming_v1": {
                            "active": True
                        }}):
            await vehicle.get_timerprogramming()
            self.assertTrue(vehicle.is_departure_timer3_supported)
            self.assertEqual(
                {
                    "timestamp":
                    datetime.fromisoformat("2022-02-22T20:00:22+00:00"),
                    "timerID":
                    "3",
                    "profileID":
                    "1",
                    "timerProgrammedStatus":
                    "notProgrammed",
                    "timerFrequency":
                    "cyclic",
                    "currentCalendarProvider": {},
                    "departureTimeOfDay":
                    "07:55",
                    "departureWeekdayMask":
                    "nnnnnyn",
                },
                vehicle.departure_timer3.__dict__,
            )
 async def test_lock_not_supported(self):
     """Test that remote locking throws exception if not supported."""
     vehicle = Vehicle(conn=None, url="dummy34")
     vehicle._discovered = True
     vehicle._services["rlu_v1"] = {"active": False}
     try:
         await vehicle.set_lock("any", "")
     except Exception as ex:
         self.assertEqual("Remote lock/unlock is not supported.",
                          ex.__str__())
    async def test_get_timerprogramming(self):
        """Vehicle with timers loaded."""
        vehicle = Vehicle(conn=TimersConnection(None), url=MOCK_VIN)
        vehicle._discovered = True

        with patch.dict(vehicle._services,
                        {"timerprogramming_v1": {
                            "active": True
                        }}):
            await vehicle.get_timerprogramming()
            self.assertIn("timer", vehicle._states)
            self.assertIsInstance(vehicle._states["timer"], TimerData)
    async def test_json(self):
        """Test JSON serialization of dict containing datetime."""
        vehicle = Vehicle(conn=None, url="dummy34")

        vehicle._discovered = True
        dtstring = "2022-02-22T02:22:20+02:00"
        d = datetime.fromisoformat(dtstring)

        with patch.dict(vehicle.attrs, {"a string": "yay", "some date": d}):
            res = f"{vehicle.json}"
            self.assertEqual(
                '{\n    "a string": "yay",\n    "some date": "2022-02-22T02:22:20+02:00"\n}',
                res)
    async def test_get_schedule_no_basic_settings(self):
        """Test that not found schedule is unsupported."""
        vehicle = Vehicle(conn=TimersConnectionNoSettings(None), url=MOCK_VIN)
        vehicle._discovered = True

        with patch.dict(vehicle._services,
                        {"timerprogramming_v1": {
                            "active": True
                        }}):
            await vehicle.get_timerprogramming()
            self.assertFalse(vehicle.is_schedule_supported(42))
            with self.assertRaises(ValueError):
                self.assertIsNone(vehicle.schedule(42))
    async def test_get_schedule1(self):
        """Test that schedule 1 support works."""
        vehicle = Vehicle(conn=TimersConnection(None), url=MOCK_VIN)
        vehicle._discovered = True

        with patch.dict(vehicle._services,
                        {"timerprogramming_v1": {
                            "active": True
                        }}):
            await vehicle.get_timerprogramming()
            self.assertFalse(vehicle.is_departure_timer1_supported)
            with self.assertRaises(ValueError):
                self.assertIsNone(vehicle.departure_timer1)
    async def test_is_last_connected_supported(self):
        """Test that parsing last connected works."""
        vehicle = Vehicle(conn=None, url="dummy34")

        vehicle._discovered = True

        with patch.dict(vehicle.attrs, {}):
            res = vehicle.is_last_connected_supported
            self.assertFalse(
                res,
                "Last connected supported returned True without attributes.")

        with patch.dict(vehicle.attrs, {"StoredVehicleDataResponse": {}}):
            res = vehicle.is_last_connected_supported
            self.assertFalse(
                res,
                "Last connected supported returned True without 'vehicleData'."
            )

        with patch.dict(vehicle.attrs,
                        {"StoredVehicleDataResponse": {
                            "vehicleData": {}
                        }}):
            res = vehicle.is_last_connected_supported
            self.assertFalse(
                res,
                "Last connected supported returned True without 'vehicleData.data'."
            )

        with patch.dict(
                vehicle.attrs,
            {"StoredVehicleDataResponse": {
                "vehicleData": {
                    "data": []
                }
            }}):
            res = vehicle.is_last_connected_supported
            self.assertFalse(
                res,
                "Last connected supported returned True without 'vehicleData.data[].field[]'."
            )

        # test with a "real" response
        with open(status_report_json_file) as f:
            data = json_loads(f.read())
        with patch.dict(vehicle.attrs, data):
            res = vehicle.is_last_connected_supported
            self.assertTrue(
                res,
                "Last connected supported returned False when it should have been True"
            )
    async def test_lock_supported(self):
        """Test that invalid locking action raises exception."""
        vehicle = Vehicle(conn=None, url="dummy34")
        vehicle._discovered = True
        vehicle._services["rlu_v1"] = {"active": True}
        try:
            self.assertFalse(await vehicle.set_lock("any", ""))
        except Exception as ex:
            self.assertEqual(ex.__str__(), "Invalid lock action: any")

        # simulate request in progress
        vehicle._requests["lock"] = {
            "id": "Foo",
            "timestamp": datetime.now() - timedelta(seconds=20)
        }
        self.assertFalse(await vehicle.set_lock("lock", ""))
    async def test_get_schedule_last_updated(self):
        """Test that not found schedule is unsupported."""
        vehicle = Vehicle(conn=TimersConnection(None), url=MOCK_VIN)
        vehicle._discovered = True

        with patch.dict(vehicle._services,
                        {"timerprogramming_v1": {
                            "active": True
                        }}):
            await vehicle.get_timerprogramming()
            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)
    async def test_last_connected(self):
        """
        Test that parsing last connected works.

        Data in json is: "tsCarSentUtc": "2022-02-14T00:00:45Z",
        and the function returns local time
        """
        vehicle = Vehicle(conn=None, url="dummy34")

        vehicle._discovered = True

        with open(status_report_json_file) as f:
            data = json_loads(f.read())
        with patch.dict(vehicle.attrs, data):
            res = vehicle.last_connected
            self.assertEqual(
                datetime.fromisoformat("2022-02-14T00:00:45+00:00").astimezone(
                    None).strftime("%Y-%m-%d %H:%M:%S"), res)