wwvb 4.0.0a0__py3-none-any.whl → 5.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
wwvb/testcli.py DELETED
@@ -1,291 +0,0 @@
1
- #!/usr/bin/python3
2
- """Test most wwvblib commandline programs"""
3
-
4
- # ruff: noqa: N802 D102
5
- # Copyright (C) 2011-2020 Jeff Epler <jepler@gmail.com>
6
- # SPDX-FileCopyrightText: 2021 Jeff Epler
7
- #
8
- # SPDX-License-Identifier: GPL-3.0-only
9
-
10
- import json
11
- import os
12
- import subprocess
13
- import sys
14
- import unittest
15
- from typing import Any, Sequence
16
-
17
- coverage_add = ("-m", "coverage", "run", "--branch", "-p") if "COVERAGE_RUN" in os.environ else ()
18
-
19
-
20
- class CLITestCase(unittest.TestCase):
21
- """Test various CLI commands within wwvbpy"""
22
-
23
- def programOutput(self, *args: str) -> str:
24
- env = os.environ.copy()
25
- env["PYTHONIOENCODING"] = "utf-8"
26
- return subprocess.check_output(args, stdin=subprocess.DEVNULL, encoding="utf-8", env=env)
27
-
28
- def moduleArgs(self, *args: str) -> Sequence[str]:
29
- return (sys.executable, *coverage_add, "-m", *args)
30
-
31
- def moduleOutput(self, *args: str) -> str:
32
- return self.programOutput(sys.executable, *coverage_add, "-m", *args)
33
-
34
- def assertProgramOutput(self, expected: str, *args: str) -> None:
35
- """Check the output from invoking a program matches the expected"""
36
- actual = self.programOutput(*args)
37
- self.assertMultiLineEqual(expected, actual, f"args={args}")
38
-
39
- def assertProgramOutputStarts(self, expected: str, *args: str) -> None:
40
- """Check the output from invoking a program matches the expected"""
41
- actual = self.programOutput(*args)
42
- self.assertMultiLineEqual(expected, actual[: len(expected)], f"args={args}")
43
-
44
- def assertModuleOutput(self, expected: str, *args: str) -> None:
45
- """Check the output from invoking a `python -m modulename` program matches the expected"""
46
- actual = self.moduleOutput(*args)
47
- self.assertMultiLineEqual(expected, actual, f"args={args}")
48
-
49
- def assertStarts(self, expected: str, actual: str, *args: str) -> None:
50
- self.assertMultiLineEqual(expected, actual[: len(expected)], f"args={args}")
51
-
52
- def assertModuleJson(self, expected: Any, *args: str) -> None:
53
- """Check the output from invoking a `python -m modulename` program matches the expected"""
54
- actual = self.moduleOutput(*args)
55
- self.assertEqual(json.loads(actual), expected)
56
-
57
- def assertModuleOutputStarts(self, expected: str, *args: str) -> None:
58
- """Check the output from invoking a `python -m modulename` program matches the expected"""
59
- actual = self.moduleOutput(*args)
60
- self.assertStarts(expected, actual, *args)
61
-
62
- def assertProgramError(self, *args: str) -> None:
63
- """Check the output from invoking a program fails"""
64
- env = os.environ.copy()
65
- env["PYTHONIOENCODING"] = "utf-8"
66
- with self.assertRaises(subprocess.SubprocessError):
67
- subprocess.check_output(
68
- args,
69
- stdin=subprocess.DEVNULL,
70
- stderr=subprocess.DEVNULL,
71
- encoding="utf-8",
72
- env=env,
73
- )
74
-
75
- def assertModuleError(self, *args: str) -> None:
76
- """Check the output from invoking a `python -m modulename` program fails"""
77
- self.assertProgramError(*self.moduleArgs(*args))
78
-
79
- def test_gen(self) -> None:
80
- """Test wwvb.gen"""
81
- self.assertModuleOutput(
82
- """\
83
- WWVB timecode: year=2020 days=001 hour=12 min=30 dst=0 ut1=-200 ly=1 ls=0
84
- 2020-001 12:30 201100000200010001020000000002000100010200100001020000010002
85
- """,
86
- "wwvb.gen",
87
- "-m",
88
- "1",
89
- "2020-1-1 12:30",
90
- )
91
-
92
- self.assertModuleOutput(
93
- """\
94
- WWVB timecode: year=2020 days=001 hour=12 min=30 dst=0 ut1=-200 ly=1 ls=0
95
- 2020-001 12:30 201100000200010001020000000002000100010200100001020000010002
96
- """,
97
- "wwvb.gen",
98
- "-m",
99
- "1",
100
- "2020",
101
- "1",
102
- "12",
103
- "30",
104
- )
105
-
106
- self.assertModuleOutput(
107
- """\
108
- WWVB timecode: year=2020 days=001 hour=12 min=30 dst=0 ut1=-200 ly=1 ls=0
109
- 2020-001 12:30 201100000200010001020000000002000100010200100001020000010002
110
- """,
111
- "wwvb.gen",
112
- "-m",
113
- "1",
114
- "2020",
115
- "1",
116
- "1",
117
- "12",
118
- "30",
119
- )
120
-
121
- self.assertModuleError("wwvb.gen", "-m", "1", "2021", "7")
122
-
123
- # Asserting a leap second
124
- self.assertModuleOutput(
125
- """\
126
- WWVB timecode: year=2020 days=001 hour=12 min=30 dst=0 ut1=-500 ly=1 ls=1
127
- 2020-001 12:30 201100000200010001020000000002000100010201010001020000011002
128
- """,
129
- "wwvb.gen",
130
- "-m",
131
- "1",
132
- "-s",
133
- "2020-1-1 12:30",
134
- )
135
-
136
- # Asserting a different ut1 value
137
- self.assertModuleOutput(
138
- """\
139
- WWVB timecode: year=2020 days=001 hour=12 min=30 dst=0 ut1=-300 ly=1 ls=0
140
- 2020-001 12:30 201100000200010001020000000002000100010200110001020000010002
141
- """,
142
- "wwvb.gen",
143
- "-m",
144
- "1",
145
- "-d",
146
- "-300",
147
- "2020-1-1 12:30",
148
- )
149
-
150
- def test_dut1table(self) -> None:
151
- """Test the dut1table program"""
152
- self.assertModuleOutputStarts(
153
- """\
154
- 1972-01-01 -0.2 182 LS on 1972-06-30 23:59:60 UTC
155
- 1972-07-01 0.8 123
156
- 1972-11-01 0.0 30
157
- 1972-12-01 -0.2 31 LS on 1972-12-31 23:59:60 UTC
158
- """,
159
- "wwvb.dut1table",
160
- )
161
-
162
- def test_json(self) -> None:
163
- """Test the JSON output format"""
164
- self.assertModuleJson(
165
- [
166
- {
167
- "year": 2021,
168
- "days": 340,
169
- "hour": 3,
170
- "minute": 40,
171
- "amplitude": "210000000200000001120011001002000000010200010001020001000002",
172
- "phase": "111110011011010101000100100110011110001110111010111101001011",
173
- },
174
- {
175
- "year": 2021,
176
- "days": 340,
177
- "hour": 3,
178
- "minute": 41,
179
- "amplitude": "210000001200000001120011001002000000010200010001020001000002",
180
- "phase": "001010011100100011000101110000100001101000001111101100000010",
181
- },
182
- ],
183
- "wwvb.gen",
184
- "-m",
185
- "2",
186
- "--style",
187
- "json",
188
- "--channel",
189
- "both",
190
- "2021-12-6 3:40",
191
- )
192
- self.assertModuleJson(
193
- [
194
- {
195
- "year": 2021,
196
- "days": 340,
197
- "hour": 3,
198
- "minute": 40,
199
- "amplitude": "210000000200000001120011001002000000010200010001020001000002",
200
- },
201
- {
202
- "year": 2021,
203
- "days": 340,
204
- "hour": 3,
205
- "minute": 41,
206
- "amplitude": "210000001200000001120011001002000000010200010001020001000002",
207
- },
208
- ],
209
- "wwvb.gen",
210
- "-m",
211
- "2",
212
- "--style",
213
- "json",
214
- "--channel",
215
- "amplitude",
216
- "2021-12-6 3:40",
217
- )
218
- self.assertModuleJson(
219
- [
220
- {
221
- "year": 2021,
222
- "days": 340,
223
- "hour": 3,
224
- "minute": 40,
225
- "phase": "111110011011010101000100100110011110001110111010111101001011",
226
- },
227
- {
228
- "year": 2021,
229
- "days": 340,
230
- "hour": 3,
231
- "minute": 41,
232
- "phase": "001010011100100011000101110000100001101000001111101100000010",
233
- },
234
- ],
235
- "wwvb.gen",
236
- "-m",
237
- "2",
238
- "--style",
239
- "json",
240
- "--channel",
241
- "phase",
242
- "2021-12-6 3:40",
243
- )
244
-
245
- def test_sextant(self) -> None:
246
- """Test the sextant output format"""
247
- self.assertModuleOutput(
248
- """\
249
- WWVB timecode: year=2021 days=340 hour=03 min=40 dst=0 ut1=-100 ly=0 ls=0 --style=sextant
250
- 2021-340 03:40 \
251
- 🬋🬩🬋🬹🬩🬹🬩🬹🬩🬹🬍🬎🬍🬎🬩🬹🬩🬹🬋🬍🬩🬹🬩🬹🬍🬎🬩🬹🬍🬎🬩🬹🬍🬎🬋🬹🬋🬎🬋🬍🬍🬎🬩🬹🬋🬎🬋🬎🬩🬹🬍🬎🬋🬎🬩🬹🬩🬹🬋🬍🬍🬎🬩🬹🬩🬹🬩🬹🬩🬹🬍🬎🬍🬎🬋🬎🬩🬹🬋🬩🬩🬹🬍🬎🬩🬹🬋🬹🬩🬹🬍🬎🬩🬹🬋🬎🬩🬹🬋🬩🬩🬹🬩🬹🬍🬎🬋🬹🬍🬎🬍🬎🬩🬹🬍🬎🬩🬹🬋🬩
252
-
253
- 2021-340 03:41 \
254
- 🬋🬍🬋🬎🬩🬹🬍🬎🬩🬹🬍🬎🬍🬎🬩🬹🬋🬹🬋🬩🬍🬎🬍🬎🬩🬹🬍🬎🬍🬎🬍🬎🬩🬹🬋🬹🬋🬎🬋🬍🬍🬎🬩🬹🬋🬎🬋🬹🬩🬹🬩🬹🬋🬎🬍🬎🬍🬎🬋🬍🬩🬹🬍🬎🬍🬎🬍🬎🬍🬎🬩🬹🬩🬹🬋🬎🬩🬹🬋🬍🬍🬎🬍🬎🬍🬎🬋🬎🬩🬹🬩🬹🬩🬹🬋🬹🬩🬹🬋🬍🬩🬹🬩🬹🬍🬎🬋🬎🬍🬎🬍🬎🬍🬎🬍🬎🬩🬹🬋🬍
255
-
256
- """,
257
- "wwvb.gen",
258
- "-m",
259
- "2",
260
- "--style",
261
- "sextant",
262
- "2021-12-6 3:40",
263
- )
264
-
265
- def test_now(self) -> None:
266
- """Test outputting timecodes for 'now'"""
267
- self.assertModuleOutputStarts(
268
- "WWVB timecode: year=",
269
- "wwvb.gen",
270
- "-m",
271
- "1",
272
- )
273
-
274
- def test_decode(self) -> None:
275
- """Test the commandline decoder"""
276
- self.assertModuleOutput(
277
- """\
278
- 201100000200100001020011001012000000010200010001020001000002
279
- year=2021 days=350 hour=22 min=30 dst=0 ut1=-100 ly=0 ls=0
280
- """,
281
- "wwvb.decode",
282
- "201100000200100001020011001012000000010200010001020001000002",
283
- )
284
-
285
- self.assertModuleOutput(
286
- """\
287
- 201101111200100001020011001012000000010200010001020001000002
288
- """,
289
- "wwvb.decode",
290
- "201101111200100001020011001012000000010200010001020001000002",
291
- )
wwvb/testdaylight.py DELETED
@@ -1,60 +0,0 @@
1
- #!/usr/bin/python3
2
- """Test of daylight saving time calculations"""
3
-
4
- # SPDX-FileCopyrightText: 2021 Jeff Epler
5
- #
6
- # SPDX-License-Identifier: GPL-3.0-only
7
-
8
- import datetime
9
- import unittest
10
-
11
- import wwvb
12
- from wwvb.tz import Mountain
13
-
14
-
15
- class TestDaylight(unittest.TestCase):
16
- """Test of daylight saving time calculations"""
17
-
18
- def test_onset(self) -> None:
19
- """Test that the onset of DST is the same in Mountain and WWVBMinute (which uses ls bits)"""
20
- for h in [8, 9, 10]:
21
- for dm in range(-1441, 1442):
22
- d = datetime.datetime(2021, 3, 14, h, 0, tzinfo=datetime.timezone.utc) + datetime.timedelta(minutes=dm)
23
- m = wwvb.WWVBMinute.from_datetime(d)
24
- self.assertEqual(
25
- m.as_datetime_local().replace(tzinfo=Mountain),
26
- d.astimezone(Mountain),
27
- )
28
-
29
- def test_end(self) -> None:
30
- """Test that the end of DST is the same in Mountain and WWVBMinute (which uses ls bits)"""
31
- for h in [7, 8, 9]:
32
- for dm in range(-1441, 1442):
33
- d = datetime.datetime(2021, 11, 7, h, 0, tzinfo=datetime.timezone.utc) + datetime.timedelta(minutes=dm)
34
- m = wwvb.WWVBMinute.from_datetime(d)
35
- self.assertEqual(
36
- m.as_datetime_local().replace(tzinfo=Mountain),
37
- d.astimezone(Mountain),
38
- )
39
-
40
- def test_midsummer(self) -> None:
41
- """Test that middle of DST is the same in Mountain and WWVBMinute (which uses ls bits)"""
42
- for h in [7, 8, 9]:
43
- for dm in (-1, 0, 1):
44
- d = datetime.datetime(2021, 7, 7, h, 0, tzinfo=datetime.timezone.utc) + datetime.timedelta(minutes=dm)
45
- m = wwvb.WWVBMinute.from_datetime(d)
46
- self.assertEqual(
47
- m.as_datetime_local().replace(tzinfo=Mountain),
48
- d.astimezone(Mountain),
49
- )
50
-
51
- def test_midwinter(self) -> None:
52
- """Test that middle of standard time is the same in Mountain and WWVBMinute (which uses ls bits)"""
53
- for h in [7, 8, 9]:
54
- for dm in (-1, 0, 1):
55
- d = datetime.datetime(2021, 12, 25, h, 0, tzinfo=datetime.timezone.utc) + datetime.timedelta(minutes=dm)
56
- m = wwvb.WWVBMinute.from_datetime(d)
57
- self.assertEqual(
58
- m.as_datetime_local().replace(tzinfo=Mountain),
59
- d.astimezone(Mountain),
60
- )
wwvb/testls.py DELETED
@@ -1,63 +0,0 @@
1
- #!/usr/bin/python3
2
- """Leap seconds tests"""
3
-
4
- # SPDX-FileCopyrightText: 2021 Jeff Epler
5
- #
6
- # SPDX-License-Identifier: GPL-3.0-only
7
-
8
- import datetime
9
- import unittest
10
-
11
- import leapseconddata
12
-
13
- import wwvb
14
-
15
- from . import iersdata
16
-
17
- ONE_DAY = datetime.timedelta(days=1)
18
-
19
-
20
- def next_month(d: datetime.date) -> datetime.date:
21
- """Return the start of the next month after the day 'd'"""
22
- d = d.replace(day=28)
23
- while True:
24
- d0 = d
25
- d = d + ONE_DAY
26
- if d.month != d0.month:
27
- return d
28
-
29
-
30
- class TestLeapSecond(unittest.TestCase):
31
- """Leap second tests"""
32
-
33
- maxDiff = 9999
34
-
35
- def test_leap(self) -> None:
36
- """Tests that the expected leap seconds all occur."""
37
- ls = leapseconddata.LeapSecondData.from_standard_source()
38
- assert ls.valid_until is not None
39
-
40
- d = iersdata.start
41
- e = min(iersdata.end, ls.valid_until)
42
- bench = [ts.start for ts in ls.leap_seconds[1:]]
43
- bench = [ts for ts in bench if d <= ts < e]
44
- leap = []
45
- while d < e:
46
- nm = next_month(d)
47
- eom = nm - ONE_DAY
48
- month_ends_dut1 = wwvb.get_dut1(eom)
49
- month_starts_dut1 = wwvb.get_dut1(nm)
50
- our_is_ls = month_ends_dut1 * month_starts_dut1 < 0
51
- if wwvb.isls(eom):
52
- assert our_is_ls
53
- self.assertLess(month_ends_dut1, 0)
54
- self.assertGreater(month_starts_dut1, 0)
55
- leap.append(nm)
56
- else:
57
- assert not our_is_ls
58
- d = datetime.datetime.combine(nm, datetime.time()).replace(tzinfo=datetime.timezone.utc)
59
- self.assertEqual(leap, bench)
60
-
61
-
62
- if __name__ == "__main__": # pragma: no cover
63
- unittest.main()
wwvb/testpm.py DELETED
@@ -1,33 +0,0 @@
1
- #!/usr/bin/python3
2
- """Test Phase Modulation Signal"""
3
-
4
- # SPDX-FileCopyrightText: 2021 Jeff Epler
5
- #
6
- # SPDX-License-Identifier: GPL-3.0-only
7
-
8
- import unittest
9
-
10
- import wwvb
11
-
12
-
13
- class TestPhaseModulation(unittest.TestCase):
14
- """Test Phase Modulation Signal"""
15
-
16
- def test_pm(self) -> None:
17
- """Compare the generated signal from a reference minute in NIST docs"""
18
- ref_am = "201100000200010011120001010002011000101201000000120010010112"
19
-
20
- ref_pm = "001110110100010010000011001000011000110100110100010110110110"
21
-
22
- ref_minute = wwvb.WWVBMinuteIERS(2012, 186, 17, 30, dst=3)
23
- ref_time = ref_minute.as_timecode()
24
-
25
- test_am = ref_time.to_am_string(["0", "1", "2"])
26
- test_pm = ref_time.to_pm_string(["0", "1"])
27
-
28
- self.assertEqual(ref_am, test_am)
29
- self.assertEqual(ref_pm, test_pm)
30
-
31
-
32
- if __name__ == "__main__": # pragma: no cover
33
- unittest.main()
wwvb/testuwwvb.py DELETED
@@ -1,221 +0,0 @@
1
- #!/usr/bin/python3
2
- """Test of uwwvb.py"""
3
- # SPDX-FileCopyrightText: 2021 Jeff Epler
4
- #
5
- # SPDX-License-Identifier: GPL-3.0-only
6
-
7
- # ruff: noqa: N802 D102
8
- import datetime
9
- import random
10
- import sys
11
- import unittest
12
- from typing import Union
13
-
14
- import adafruit_datetime
15
- import uwwvb
16
- import zoneinfo
17
-
18
- import wwvb
19
-
20
- EitherDatetimeOrNone = Union[None, datetime.datetime, adafruit_datetime.datetime]
21
-
22
-
23
- class WWVBRoundtrip(unittest.TestCase):
24
- """tests of uwwvb.py"""
25
-
26
- def assertDateTimeEqualExceptTzInfo(self, a: EitherDatetimeOrNone, b: EitherDatetimeOrNone) -> None:
27
- """Test two datetime objects for equality
28
-
29
- This equality test excludes tzinfo, and allows adafruit_datetime and core datetime modules to compare equal
30
- """
31
- assert a
32
- assert b
33
- self.assertEqual(
34
- (a.year, a.month, a.day, a.hour, a.minute, a.second, a.microsecond),
35
- (b.year, b.month, b.day, b.hour, b.minute, b.second, b.microsecond),
36
- )
37
-
38
- def test_decode(self) -> None:
39
- """Test decoding of some minutes including a leap second.
40
-
41
- Each minute must decode and match the primary decoder.
42
- """
43
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc))
44
- assert minute
45
- decoder = uwwvb.WWVBDecoder()
46
- decoder.update(uwwvb.MARK)
47
- any_leap_second = False
48
- for _ in range(20):
49
- timecode = minute.as_timecode()
50
- decoded = None
51
- if len(timecode.am) == 61:
52
- any_leap_second = True
53
- for code in timecode.am:
54
- decoded = uwwvb.decode_wwvb(decoder.update(int(code))) or decoded
55
- assert decoded
56
- self.assertDateTimeEqualExceptTzInfo(
57
- minute.as_datetime_utc(),
58
- uwwvb.as_datetime_utc(decoded),
59
- )
60
- minute = minute.next_minute()
61
- self.assertTrue(any_leap_second)
62
-
63
- def test_roundtrip(self) -> None:
64
- """Test that some big range of times all decode the same as the primary decoder"""
65
- dt = datetime.datetime(2002, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
66
- delta = datetime.timedelta(minutes=7182 if sys.implementation.name == "cpython" else 86400 - 7182)
67
- while dt.year < 2013:
68
- minute = wwvb.WWVBMinuteIERS.from_datetime(dt)
69
- assert minute
70
- decoded = uwwvb.decode_wwvb([int(i) for i in minute.as_timecode().am])
71
- assert decoded
72
- self.assertDateTimeEqualExceptTzInfo(minute.as_datetime_utc(), uwwvb.as_datetime_utc(decoded))
73
- dt = dt + delta
74
-
75
- def test_dst(self) -> None:
76
- """Test of DST as handled by the small decoder"""
77
- for dt in (
78
- datetime.datetime(2021, 3, 14, 8, 59, tzinfo=datetime.timezone.utc),
79
- datetime.datetime(2021, 3, 14, 9, 00, tzinfo=datetime.timezone.utc),
80
- datetime.datetime(2021, 3, 14, 9, 1, tzinfo=datetime.timezone.utc),
81
- datetime.datetime(2021, 3, 15, 8, 59, tzinfo=datetime.timezone.utc),
82
- datetime.datetime(2021, 3, 15, 9, 00, tzinfo=datetime.timezone.utc),
83
- datetime.datetime(2021, 3, 15, 9, 1, tzinfo=datetime.timezone.utc),
84
- datetime.datetime(2021, 11, 7, 8, 59, tzinfo=datetime.timezone.utc),
85
- datetime.datetime(2021, 11, 7, 9, 00, tzinfo=datetime.timezone.utc),
86
- datetime.datetime(2021, 11, 7, 9, 1, tzinfo=datetime.timezone.utc),
87
- datetime.datetime(2021, 11, 8, 8, 59, tzinfo=datetime.timezone.utc),
88
- datetime.datetime(2021, 11, 8, 9, 00, tzinfo=datetime.timezone.utc),
89
- datetime.datetime(2021, 11, 8, 9, 1, tzinfo=datetime.timezone.utc),
90
- datetime.datetime(2021, 7, 7, 9, 1, tzinfo=datetime.timezone.utc),
91
- ):
92
- minute = wwvb.WWVBMinuteIERS.from_datetime(dt)
93
- decoded = uwwvb.decode_wwvb([int(i) for i in minute.as_timecode().am])
94
- assert decoded
95
- self.assertDateTimeEqualExceptTzInfo(minute.as_datetime_local(), uwwvb.as_datetime_local(decoded))
96
-
97
- decoded = uwwvb.decode_wwvb([int(i) for i in minute.as_timecode().am])
98
- assert decoded
99
- self.assertDateTimeEqualExceptTzInfo(
100
- minute.as_datetime_local(dst_observed=False),
101
- uwwvb.as_datetime_local(decoded, dst_observed=False),
102
- )
103
-
104
- def test_noise(self) -> None:
105
- """Test of the state-machine decoder when faced with pseudorandom noise"""
106
- minute = wwvb.WWVBMinuteIERS.from_datetime(
107
- datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc),
108
- )
109
- r = random.Random(408)
110
- junk = [
111
- r.choice(
112
- [
113
- wwvb.AmplitudeModulation.MARK,
114
- wwvb.AmplitudeModulation.ONE,
115
- wwvb.AmplitudeModulation.ZERO,
116
- ],
117
- )
118
- for _ in range(480)
119
- ]
120
- timecode = minute.as_timecode()
121
- test_input = [*junk, wwvb.AmplitudeModulation.MARK, *timecode.am]
122
- decoder = uwwvb.WWVBDecoder()
123
- for code in test_input[:-1]:
124
- decoded = decoder.update(code)
125
- self.assertIsNone(decoded)
126
- minute_maybe = decoder.update(wwvb.AmplitudeModulation.MARK)
127
- assert minute_maybe
128
- decoded_minute = uwwvb.decode_wwvb(minute_maybe)
129
- assert decoded_minute
130
- self.assertDateTimeEqualExceptTzInfo(
131
- minute.as_datetime_utc(),
132
- uwwvb.as_datetime_utc(decoded_minute),
133
- )
134
- self.assertDateTimeEqualExceptTzInfo(
135
- minute.as_datetime_local(),
136
- uwwvb.as_datetime_local(decoded_minute),
137
- )
138
-
139
- def test_noise2(self) -> None:
140
- """Test of the full minute decoder with targeted errors to get full coverage"""
141
- minute = wwvb.WWVBMinuteIERS.from_datetime(
142
- datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc),
143
- )
144
- timecode = minute.as_timecode()
145
- decoded = uwwvb.decode_wwvb([int(i) for i in timecode.am])
146
- self.assertIsNotNone(decoded)
147
- for position in uwwvb.always_mark:
148
- test_input = [int(i) for i in timecode.am]
149
- for noise in (0, 1):
150
- test_input[position] = noise
151
- decoded = uwwvb.decode_wwvb(test_input)
152
- self.assertIsNone(decoded)
153
- for position in uwwvb.always_zero:
154
- test_input = [int(i) for i in timecode.am]
155
- for noise in (1, 2):
156
- test_input[position] = noise
157
- decoded = uwwvb.decode_wwvb(test_input)
158
- self.assertIsNone(decoded)
159
- for i in range(8):
160
- if i in (0b101, 0b010): # Test the 6 impossible bit-combos
161
- continue
162
- test_input = [int(i) for i in timecode.am]
163
- test_input[36] = i & 1
164
- test_input[37] = (i >> 1) & 1
165
- test_input[38] = (i >> 2) & 1
166
- decoded = uwwvb.decode_wwvb(test_input)
167
- self.assertIsNone(decoded)
168
- # Invalid year-day
169
- test_input = [int(i) for i in timecode.am]
170
- test_input[22] = 1
171
- test_input[23] = 1
172
- test_input[25] = 1
173
- decoded = uwwvb.decode_wwvb(test_input)
174
- self.assertIsNone(decoded)
175
-
176
- def test_noise3(self) -> None:
177
- """Test impossible BCD values"""
178
- minute = wwvb.WWVBMinuteIERS.from_datetime(
179
- datetime.datetime(2012, 6, 30, 23, 50, tzinfo=datetime.timezone.utc),
180
- )
181
- timecode = minute.as_timecode()
182
-
183
- for poslist in [
184
- [1, 2, 3, 4], # tens minutes
185
- [5, 6, 7, 8], # ones minutes
186
- [15, 16, 17, 18], # tens hours
187
- [25, 26, 27, 28], # tens days
188
- [30, 31, 32, 33], # ones days
189
- [40, 41, 42, 43], # tens years
190
- [45, 46, 47, 48], # ones years
191
- [50, 51, 52, 53], # ones dut1
192
- ]:
193
- with self.subTest(test=poslist):
194
- test_input = [int(i) for i in timecode.am]
195
- for pi in poslist:
196
- test_input[pi] = 1
197
- decoded = uwwvb.decode_wwvb(test_input)
198
- self.assertIsNone(decoded)
199
-
200
- def test_str(self) -> None:
201
- """Test the str() of a WWVBDecoder"""
202
- self.assertEqual(str(uwwvb.WWVBDecoder()), "<WWVBDecoder 1 []>")
203
-
204
- def test_near_year_bug(self) -> None:
205
- """Test for a bug seen in another WWVB implementaiton
206
-
207
- .. in which the hours after UTC midnight on 12-31 of a leap year would
208
- be shown incorrectly. Check that we don't have that bug.
209
- """
210
- minute = wwvb.WWVBMinuteIERS.from_datetime(datetime.datetime(2021, 1, 1, 0, 0, tzinfo=datetime.timezone.utc))
211
- timecode = minute.as_timecode()
212
- decoded = uwwvb.decode_wwvb([int(i) for i in timecode.am])
213
- assert decoded
214
- self.assertDateTimeEqualExceptTzInfo(
215
- datetime.datetime(2020, 12, 31, 17, 00, tzinfo=zoneinfo.ZoneInfo("America/Denver")), # Mountain time!
216
- uwwvb.as_datetime_local(decoded),
217
- )
218
-
219
-
220
- if __name__ == "__main__": # pragma no cover
221
- unittest.main()