Merge pull request #140 from jepler/more-error-detection
This commit is contained in:
commit
c9a0b64195
2 changed files with 44 additions and 9 deletions
|
|
@ -24,12 +24,6 @@ SECOND = datetime.timedelta(seconds=1)
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
def _require(x: T | None) -> T:
|
|
||||||
"""Check an Optional item is not None."""
|
|
||||||
assert x is not None
|
|
||||||
return x
|
|
||||||
|
|
||||||
|
|
||||||
def _removeprefix(s: str, p: str) -> str:
|
def _removeprefix(s: str, p: str) -> str:
|
||||||
if s.startswith(p):
|
if s.startswith(p):
|
||||||
return s[len(p) :]
|
return s[len(p) :]
|
||||||
|
|
@ -689,7 +683,7 @@ class WWVBMinute(_WWVBMinute):
|
||||||
return cls(u.tm_year, u.tm_yday, u.tm_hour, u.tm_min, ut1=newut1, ls=newls)
|
return cls(u.tm_year, u.tm_yday, u.tm_hour, u.tm_min, ut1=newut1, ls=newls)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_timecode_am(cls, t: WWVBTimecode) -> WWVBMinute | None:
|
def from_timecode_am(cls, t: WWVBTimecode) -> WWVBMinute | None: # noqa: PLR0912
|
||||||
"""Construct a WWVBMinute from a WWVBTimecode"""
|
"""Construct a WWVBMinute from a WWVBTimecode"""
|
||||||
for i in (0, 9, 19, 29, 39, 49, 59):
|
for i in (0, 9, 19, 29, 39, 49, 59):
|
||||||
if t.am[i] != AmplitudeModulation.MARK:
|
if t.am[i] != AmplitudeModulation.MARK:
|
||||||
|
|
@ -704,9 +698,13 @@ class WWVBMinute(_WWVBMinute):
|
||||||
minute = t._get_am_bcd(1, 2, 3, 5, 6, 7, 8)
|
minute = t._get_am_bcd(1, 2, 3, 5, 6, 7, 8)
|
||||||
if minute is None:
|
if minute is None:
|
||||||
return None
|
return None
|
||||||
|
if minute >= 60:
|
||||||
|
return None
|
||||||
hour = t._get_am_bcd(12, 13, 15, 16, 17, 18)
|
hour = t._get_am_bcd(12, 13, 15, 16, 17, 18)
|
||||||
if hour is None:
|
if hour is None:
|
||||||
return None
|
return None
|
||||||
|
if hour >= 24:
|
||||||
|
return None
|
||||||
days = t._get_am_bcd(22, 23, 25, 26, 27, 28, 30, 31, 32, 33)
|
days = t._get_am_bcd(22, 23, 25, 26, 27, 28, 30, 31, 32, 33)
|
||||||
if days is None:
|
if days is None:
|
||||||
return None
|
return None
|
||||||
|
|
@ -723,7 +721,9 @@ class WWVBMinute(_WWVBMinute):
|
||||||
if days > 366 or (not ly and days > 365):
|
if days > 366 or (not ly and days > 365):
|
||||||
return None
|
return None
|
||||||
ls = bool(t.am[56])
|
ls = bool(t.am[56])
|
||||||
dst = _require(t._get_am_bcd(57, 58))
|
dst = t._get_am_bcd(57, 58)
|
||||||
|
if dst is None:
|
||||||
|
return None
|
||||||
return cls(year, days, hour, minute, dst, ut1, ls, ly)
|
return cls(year, days, hour, minute, dst, ut1, ls, ly)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -784,7 +784,10 @@ class WWVBTimecode:
|
||||||
The the bits ``self.am[poslist[i]]`` in MSB order are converted from
|
The the bits ``self.am[poslist[i]]`` in MSB order are converted from
|
||||||
BCD to integer
|
BCD to integer
|
||||||
"""
|
"""
|
||||||
pos = reversed(poslist)
|
pos = list(poslist)[::-1]
|
||||||
|
for p in pos:
|
||||||
|
if self.am[p] not in {AmplitudeModulation.ZERO, AmplitudeModulation.ONE}:
|
||||||
|
return None
|
||||||
val = [bool(self.am[p]) for p in pos]
|
val = [bool(self.am[p]) for p in pos]
|
||||||
result = 0
|
result = 0
|
||||||
base = 1
|
base = 1
|
||||||
|
|
|
||||||
|
|
@ -395,6 +395,38 @@ class WWVBRoundtrip(unittest.TestCase):
|
||||||
self.assertEqual(WWVBMinute2k(2070, 1, 1, 0, 0).year, 2070)
|
self.assertEqual(WWVBMinute2k(2070, 1, 1, 0, 0).year, 2070)
|
||||||
self.assertEqual(WWVBMinute2k(2099, 1, 1, 0, 0).year, 2099)
|
self.assertEqual(WWVBMinute2k(2099, 1, 1, 0, 0).year, 2099)
|
||||||
|
|
||||||
|
def test_invalid_minute(self) -> None:
|
||||||
|
"""Check that minute 61 is not valid in an AM timecode"""
|
||||||
|
base_minute = wwvb.WWVBMinute(2021, 1, 1, 0, 0)
|
||||||
|
minute = base_minute.as_timecode()
|
||||||
|
minute._put_am_bcd(61, 1, 2, 3, 5, 6, 7, 8) # valid BCD, invalid minute
|
||||||
|
decoded_minute = wwvb.WWVBMinute.from_timecode_am(minute)
|
||||||
|
assert decoded_minute is None
|
||||||
|
|
||||||
|
def test_invalid_hour(self) -> None:
|
||||||
|
"""Check that hour 25 is not valid in an AM timecode"""
|
||||||
|
base_minute = wwvb.WWVBMinute(2021, 1, 1, 0, 0)
|
||||||
|
minute = base_minute.as_timecode()
|
||||||
|
minute._put_am_bcd(29, 12, 13, 15, 16, 17, 18) # valid BCD, invalid hour
|
||||||
|
decoded_minute = wwvb.WWVBMinute.from_timecode_am(minute)
|
||||||
|
assert decoded_minute is None
|
||||||
|
|
||||||
|
def test_invalid_bcd_day(self) -> None:
|
||||||
|
"""Check that invalid BCD is detected in AM timecode"""
|
||||||
|
base_minute = wwvb.WWVBMinute(2021, 1, 1, 0, 0)
|
||||||
|
minute = base_minute.as_timecode()
|
||||||
|
minute.am[30:34] = [wwvb.AmplitudeModulation.ONE] * 4 # invalid BCD 0xf
|
||||||
|
decoded_minute = wwvb.WWVBMinute.from_timecode_am(minute)
|
||||||
|
assert decoded_minute is None
|
||||||
|
|
||||||
|
def test_invalid_mark(self) -> None:
|
||||||
|
"""Check that invalid presence of MARK in a data field is detected"""
|
||||||
|
base_minute = wwvb.WWVBMinute(2021, 1, 1, 0, 0)
|
||||||
|
minute = base_minute.as_timecode()
|
||||||
|
minute.am[57] = wwvb.AmplitudeModulation.MARK
|
||||||
|
decoded_minute = wwvb.WWVBMinute.from_timecode_am(minute)
|
||||||
|
assert decoded_minute is None
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue