1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
|
"""Unit test for KNX datetime objects."""
import datetime
from typing import Any
import pytest
from xknx.dpt import DPTArray, DPTBinary, DPTDateTime
from xknx.dpt.dpt_19 import KNXDateTime, KNXDayOfWeek
from xknx.exceptions import ConversionError, CouldNotParseTelegram
class TestKNXDateTime:
"""Test class for KNX datetime objects."""
@pytest.mark.parametrize(
("data", "value"),
[
(
{
"year": 1900,
"month": 1,
"day": 1,
"hour": 0,
"minutes": 0,
"seconds": 0,
},
KNXDateTime(1900, 1, 1, 0, 0, 0),
),
(
{
"year": 2155,
"month": 12,
"day": 31,
"hour": 23,
"minutes": 59,
"seconds": 59,
"day_of_week": "monday",
},
KNXDateTime(
2155,
12,
31,
23,
59,
59,
day_of_week=KNXDayOfWeek.MONDAY,
),
),
(
{
"year": 2017,
"month": 11,
"day": 28,
"hour": 23,
"minutes": 7,
"seconds": 24,
"day_of_week": "any_day",
"fault": True,
"working_day": True,
"dst": True,
"external_sync": True,
"source_reliable": True,
},
KNXDateTime(
2017,
11,
28,
23,
7,
24,
day_of_week=KNXDayOfWeek.ANY_DAY,
fault=True,
working_day=True,
dst=True,
external_sync=True,
source_reliable=True,
),
),
],
)
def test_dict(self, data: dict[str, Any], value: KNXDateTime) -> None:
"""Test from_dict and as_dict methods."""
assert KNXDateTime.from_dict(data) == value
default_dict = {
"day_of_week": None,
"fault": False,
"working_day": None,
"dst": False,
"external_sync": False,
"source_reliable": False,
}
assert value.as_dict() == default_dict | data
@pytest.mark.parametrize(
"data",
[
# invalid data
{"hours": 1}, # additional "s" in "hours"
{
"year": 1900,
"month": 1,
"day": 1,
"hour": 0,
"minutes": 0,
"seconds": 0,
"invalid": True,
},
],
)
def test_dict_invalid(self, data: Any) -> None:
"""Test from_dict and as_dict methods."""
with pytest.raises(ValueError):
KNXDateTime.from_dict(data)
@pytest.mark.parametrize(
("dt", "value"),
[
(
datetime.datetime(2024, 7, 28, 22, 59, 17),
KNXDateTime(2024, 7, 28, 22, 59, 17),
),
(
datetime.datetime(1999, 3, 31),
KNXDateTime(1999, 3, 31, 0, 0, 0), # datetime time defaults to 0:00:00
),
],
)
def test_as_datetime(self, dt: datetime.datetime, value: KNXDateTime) -> None:
"""Test from_time and as_time methods."""
assert KNXDateTime.from_datetime(dt) == value
assert value.as_datetime() == dt
class TestDPTDateTime:
"""Test class for KNX datetime objects."""
@pytest.mark.parametrize(
("value", "raw"),
[
(
KNXDateTime(2017, 11, 28, 23, 7, 24),
(0x75, 0x0B, 0x1C, 0x17, 0x07, 0x18, 0x24, 0x00),
),
(
KNXDateTime(1900, 1, 1, 0, 0, 0),
(0x00, 0x1, 0x1, 0x00, 0x00, 0x00, 0x24, 0x00),
),
(
KNXDateTime(2155, 12, 31, 23, 59, 59, day_of_week=KNXDayOfWeek.SUNDAY),
(0xFF, 0x0C, 0x1F, 0xF7, 0x3B, 0x3B, 0x20, 0x00),
),
],
)
def test_parse(self, value: KNXDateTime, raw: tuple[int, ...]) -> None:
"""Test parsing and streaming."""
knx_value = DPTDateTime.to_knx(value)
assert knx_value == DPTArray(raw)
assert DPTDateTime.from_knx(knx_value) == value
def test_from_knx_wrong_value(self) -> None:
"""Test parsing DPTDateTime from KNX with wrong binary values."""
with pytest.raises(CouldNotParseTelegram):
DPTDateTime.from_knx(DPTArray((0xF8, 0x23)))
with pytest.raises(ConversionError):
# (second byte exceeds value...)
DPTDateTime.from_knx(
DPTArray((0xFF, 0x0D, 0x1F, 0xF7, 0x3B, 0x3B, 0x00, 0x00))
)
with pytest.raises(CouldNotParseTelegram):
DPTDateTime.from_knx(DPTBinary(True))
def test_to_knx_wrong_value(self) -> None:
"""Test parsing from DPTDateTime object from wrong value."""
with pytest.raises(ConversionError):
# year out of range
DPTDateTime.to_knx(KNXDateTime(1889, 1, 1, 0, 0, 0))
with pytest.raises(ConversionError):
# day out of range (0)
DPTDateTime.to_knx(KNXDateTime(2000, 1, 0, 0, 0, 0))
with pytest.raises(ConversionError):
# hour out of range
DPTDateTime.to_knx(KNXDateTime(2000, 1, 1, 25, 0, 0))
with pytest.raises(ConversionError):
# minutes out of range
DPTDateTime.to_knx(KNXDateTime(2000, 1, 1, 1, 60, 0))
with pytest.raises(ConversionError):
# seconds out of range
DPTDateTime.to_knx(KNXDateTime(2000, 1, 1, 1, 0, 60))
with pytest.raises(ConversionError):
# seconds out of range at hour 24
DPTDateTime.to_knx(KNXDateTime(2000, 1, 1, 24, 0, 1))
with pytest.raises(ConversionError):
DPTDateTime.to_knx("hello")
with pytest.raises(ConversionError):
DPTDateTime.to_knx((1, 2, 3))
|