291 lines
9.9 KiB
Python
291 lines
9.9 KiB
Python
#!/usr/bin/python3
|
|
"""Test most wwvblib commandline programs"""
|
|
|
|
# ruff: noqa: N802 D102
|
|
# SPDX-FileCopyrightText: 2021-2024 Jeff Epler
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
from collections.abc import Sequence
|
|
from typing import Any
|
|
|
|
coverage_add = ("-m", "coverage", "run", "--branch", "-p") if "COVERAGE_RUN" in os.environ else ()
|
|
|
|
|
|
class CLITestCase(unittest.TestCase):
|
|
"""Test various CLI commands within wwvbpy"""
|
|
|
|
def programOutput(self, *args: str) -> str:
|
|
env = os.environ.copy()
|
|
env["PYTHONIOENCODING"] = "utf-8"
|
|
return subprocess.check_output(args, stdin=subprocess.DEVNULL, encoding="utf-8", env=env)
|
|
|
|
def moduleArgs(self, *args: str) -> Sequence[str]:
|
|
return (sys.executable, *coverage_add, "-m", *args)
|
|
|
|
def moduleOutput(self, *args: str) -> str:
|
|
return self.programOutput(sys.executable, *coverage_add, "-m", *args)
|
|
|
|
def assertProgramOutput(self, expected: str, *args: str) -> None:
|
|
"""Check the output from invoking a program matches the expected"""
|
|
actual = self.programOutput(*args)
|
|
self.assertMultiLineEqual(expected, actual, f"args={args}")
|
|
|
|
def assertProgramOutputStarts(self, expected: str, *args: str) -> None:
|
|
"""Check the output from invoking a program matches the expected"""
|
|
actual = self.programOutput(*args)
|
|
self.assertMultiLineEqual(expected, actual[: len(expected)], f"args={args}")
|
|
|
|
def assertModuleOutput(self, expected: str, *args: str) -> None:
|
|
"""Check the output from invoking a `python -m modulename` program matches the expected"""
|
|
actual = self.moduleOutput(*args)
|
|
self.assertMultiLineEqual(expected, actual, f"args={args}")
|
|
|
|
def assertStarts(self, expected: str, actual: str, *args: str) -> None:
|
|
self.assertMultiLineEqual(expected, actual[: len(expected)], f"args={args}")
|
|
|
|
def assertModuleJson(self, expected: Any, *args: str) -> None:
|
|
"""Check the output from invoking a `python -m modulename` program matches the expected"""
|
|
actual = self.moduleOutput(*args)
|
|
self.assertEqual(json.loads(actual), expected)
|
|
|
|
def assertModuleOutputStarts(self, expected: str, *args: str) -> None:
|
|
"""Check the output from invoking a `python -m modulename` program matches the expected"""
|
|
actual = self.moduleOutput(*args)
|
|
self.assertStarts(expected, actual, *args)
|
|
|
|
def assertProgramError(self, *args: str) -> None:
|
|
"""Check the output from invoking a program fails"""
|
|
env = os.environ.copy()
|
|
env["PYTHONIOENCODING"] = "utf-8"
|
|
with self.assertRaises(subprocess.SubprocessError):
|
|
subprocess.check_output(
|
|
args,
|
|
stdin=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
encoding="utf-8",
|
|
env=env,
|
|
)
|
|
|
|
def assertModuleError(self, *args: str) -> None:
|
|
"""Check the output from invoking a `python -m modulename` program fails"""
|
|
self.assertProgramError(*self.moduleArgs(*args))
|
|
|
|
def test_gen(self) -> None:
|
|
"""Test wwvb.gen"""
|
|
self.assertModuleOutput(
|
|
"""\
|
|
WWVB timecode: year=2020 days=001 hour=12 min=30 dst=0 ut1=-200 ly=1 ls=0
|
|
2020-001 12:30 201100000200010001020000000002000100010200100001020000010002
|
|
""",
|
|
"wwvb.gen",
|
|
"-m",
|
|
"1",
|
|
"2020-1-1 12:30",
|
|
)
|
|
|
|
self.assertModuleOutput(
|
|
"""\
|
|
WWVB timecode: year=2020 days=001 hour=12 min=30 dst=0 ut1=-200 ly=1 ls=0
|
|
2020-001 12:30 201100000200010001020000000002000100010200100001020000010002
|
|
""",
|
|
"wwvb.gen",
|
|
"-m",
|
|
"1",
|
|
"2020",
|
|
"1",
|
|
"12",
|
|
"30",
|
|
)
|
|
|
|
self.assertModuleOutput(
|
|
"""\
|
|
WWVB timecode: year=2020 days=001 hour=12 min=30 dst=0 ut1=-200 ly=1 ls=0
|
|
2020-001 12:30 201100000200010001020000000002000100010200100001020000010002
|
|
""",
|
|
"wwvb.gen",
|
|
"-m",
|
|
"1",
|
|
"2020",
|
|
"1",
|
|
"1",
|
|
"12",
|
|
"30",
|
|
)
|
|
|
|
self.assertModuleError("wwvb.gen", "-m", "1", "2021", "7")
|
|
|
|
# Asserting a leap second
|
|
self.assertModuleOutput(
|
|
"""\
|
|
WWVB timecode: year=2020 days=001 hour=12 min=30 dst=0 ut1=-500 ly=1 ls=1
|
|
2020-001 12:30 201100000200010001020000000002000100010201010001020000011002
|
|
""",
|
|
"wwvb.gen",
|
|
"-m",
|
|
"1",
|
|
"-s",
|
|
"2020-1-1 12:30",
|
|
)
|
|
|
|
# Asserting a different ut1 value
|
|
self.assertModuleOutput(
|
|
"""\
|
|
WWVB timecode: year=2020 days=001 hour=12 min=30 dst=0 ut1=-300 ly=1 ls=0
|
|
2020-001 12:30 201100000200010001020000000002000100010200110001020000010002
|
|
""",
|
|
"wwvb.gen",
|
|
"-m",
|
|
"1",
|
|
"-d",
|
|
"-300",
|
|
"2020-1-1 12:30",
|
|
)
|
|
|
|
def test_dut1table(self) -> None:
|
|
"""Test the dut1table program"""
|
|
self.assertModuleOutputStarts(
|
|
"""\
|
|
1972-01-01 -0.2 182 LS on 1972-06-30 23:59:60 UTC
|
|
1972-07-01 0.8 123
|
|
1972-11-01 0.0 30
|
|
1972-12-01 -0.2 31 LS on 1972-12-31 23:59:60 UTC
|
|
""",
|
|
"wwvb.dut1table",
|
|
)
|
|
|
|
def test_json(self) -> None:
|
|
"""Test the JSON output format"""
|
|
self.assertModuleJson(
|
|
[
|
|
{
|
|
"year": 2021,
|
|
"days": 340,
|
|
"hour": 3,
|
|
"minute": 40,
|
|
"amplitude": "210000000200000001120011001002000000010200010001020001000002",
|
|
"phase": "111110011011010101000100100110011110001110111010111101001011",
|
|
},
|
|
{
|
|
"year": 2021,
|
|
"days": 340,
|
|
"hour": 3,
|
|
"minute": 41,
|
|
"amplitude": "210000001200000001120011001002000000010200010001020001000002",
|
|
"phase": "001010011100100011000101110000100001101000001111101100000010",
|
|
},
|
|
],
|
|
"wwvb.gen",
|
|
"-m",
|
|
"2",
|
|
"--style",
|
|
"json",
|
|
"--channel",
|
|
"both",
|
|
"2021-12-6 3:40",
|
|
)
|
|
self.assertModuleJson(
|
|
[
|
|
{
|
|
"year": 2021,
|
|
"days": 340,
|
|
"hour": 3,
|
|
"minute": 40,
|
|
"amplitude": "210000000200000001120011001002000000010200010001020001000002",
|
|
},
|
|
{
|
|
"year": 2021,
|
|
"days": 340,
|
|
"hour": 3,
|
|
"minute": 41,
|
|
"amplitude": "210000001200000001120011001002000000010200010001020001000002",
|
|
},
|
|
],
|
|
"wwvb.gen",
|
|
"-m",
|
|
"2",
|
|
"--style",
|
|
"json",
|
|
"--channel",
|
|
"amplitude",
|
|
"2021-12-6 3:40",
|
|
)
|
|
self.assertModuleJson(
|
|
[
|
|
{
|
|
"year": 2021,
|
|
"days": 340,
|
|
"hour": 3,
|
|
"minute": 40,
|
|
"phase": "111110011011010101000100100110011110001110111010111101001011",
|
|
},
|
|
{
|
|
"year": 2021,
|
|
"days": 340,
|
|
"hour": 3,
|
|
"minute": 41,
|
|
"phase": "001010011100100011000101110000100001101000001111101100000010",
|
|
},
|
|
],
|
|
"wwvb.gen",
|
|
"-m",
|
|
"2",
|
|
"--style",
|
|
"json",
|
|
"--channel",
|
|
"phase",
|
|
"2021-12-6 3:40",
|
|
)
|
|
|
|
def test_sextant(self) -> None:
|
|
"""Test the sextant output format"""
|
|
self.assertModuleOutput(
|
|
"""\
|
|
WWVB timecode: year=2021 days=340 hour=03 min=40 dst=0 ut1=-100 ly=0 ls=0 --style=sextant
|
|
2021-340 03:40 \
|
|
🬋🬩🬋🬹🬩🬹🬩🬹🬩🬹🬍🬎🬍🬎🬩🬹🬩🬹🬋🬍🬩🬹🬩🬹🬍🬎🬩🬹🬍🬎🬩🬹🬍🬎🬋🬹🬋🬎🬋🬍🬍🬎🬩🬹🬋🬎🬋🬎🬩🬹🬍🬎🬋🬎🬩🬹🬩🬹🬋🬍🬍🬎🬩🬹🬩🬹🬩🬹🬩🬹🬍🬎🬍🬎🬋🬎🬩🬹🬋🬩🬩🬹🬍🬎🬩🬹🬋🬹🬩🬹🬍🬎🬩🬹🬋🬎🬩🬹🬋🬩🬩🬹🬩🬹🬍🬎🬋🬹🬍🬎🬍🬎🬩🬹🬍🬎🬩🬹🬋🬩
|
|
|
|
2021-340 03:41 \
|
|
🬋🬍🬋🬎🬩🬹🬍🬎🬩🬹🬍🬎🬍🬎🬩🬹🬋🬹🬋🬩🬍🬎🬍🬎🬩🬹🬍🬎🬍🬎🬍🬎🬩🬹🬋🬹🬋🬎🬋🬍🬍🬎🬩🬹🬋🬎🬋🬹🬩🬹🬩🬹🬋🬎🬍🬎🬍🬎🬋🬍🬩🬹🬍🬎🬍🬎🬍🬎🬍🬎🬩🬹🬩🬹🬋🬎🬩🬹🬋🬍🬍🬎🬍🬎🬍🬎🬋🬎🬩🬹🬩🬹🬩🬹🬋🬹🬩🬹🬋🬍🬩🬹🬩🬹🬍🬎🬋🬎🬍🬎🬍🬎🬍🬎🬍🬎🬩🬹🬋🬍
|
|
|
|
""",
|
|
"wwvb.gen",
|
|
"-m",
|
|
"2",
|
|
"--style",
|
|
"sextant",
|
|
"2021-12-6 3:40",
|
|
)
|
|
|
|
def test_now(self) -> None:
|
|
"""Test outputting timecodes for 'now'"""
|
|
self.assertModuleOutputStarts(
|
|
"WWVB timecode: year=",
|
|
"wwvb.gen",
|
|
"-m",
|
|
"1",
|
|
)
|
|
|
|
def test_decode(self) -> None:
|
|
"""Test the commandline decoder"""
|
|
self.assertModuleOutput(
|
|
"""\
|
|
201100000200100001020011001012000000010200010001020001000002
|
|
year=2021 days=350 hour=22 min=30 dst=0 ut1=-100 ly=0 ls=0
|
|
""",
|
|
"wwvb.decode",
|
|
"201100000200100001020011001012000000010200010001020001000002",
|
|
)
|
|
|
|
self.assertModuleOutput(
|
|
"""\
|
|
201101111200100001020011001012000000010200010001020001000002
|
|
""",
|
|
"wwvb.decode",
|
|
"201101111200100001020011001012000000010200010001020001000002",
|
|
)
|