mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-22 11:17:49 +10:00
emdashes begone (#10847)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"""`boards.py` filter and enumeration correctness.
|
||||
|
||||
Runs against the real `pio project config` output of this firmware repo —
|
||||
Runs against the real `pio project config` output of this firmware repo -
|
||||
validates that filter predicates match expected envs and don't drift if
|
||||
variants get reorganized.
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Unit tests for the `build_flags` injection on `flash.build()`.
|
||||
|
||||
We don't actually run pio here — too slow, requires hardware-aware envs.
|
||||
We don't actually run pio here - too slow, requires hardware-aware envs.
|
||||
We test the translation layer (`_build_flags_env`) and that the env vars
|
||||
are threaded through pio.run correctly via mock.
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""TCP transport plumbing in connection.py + devices.py.
|
||||
|
||||
Pure-Python tests — no real device or daemon required. Mocks `TCPInterface`
|
||||
Pure-Python tests - no real device or daemon required. Mocks `TCPInterface`
|
||||
when exercising `connect()`.
|
||||
"""
|
||||
|
||||
@@ -171,7 +171,7 @@ class TestResolvePort:
|
||||
self, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
monkeypatch.setenv("MESHTASTIC_MCP_TCP_HOST", "localhost")
|
||||
# Don't patch list_devices — let the real env-var path run, but stub
|
||||
# Don't patch list_devices - let the real env-var path run, but stub
|
||||
# the USB enumeration to keep the test hermetic.
|
||||
with patch("meshtastic_mcp.devices.list_ports.comports", return_value=[]):
|
||||
assert connection.resolve_port(None) == "tcp://localhost:4403"
|
||||
@@ -208,7 +208,7 @@ class TestDevicesTcpEntry:
|
||||
self, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
# `list_devices` is the diagnostic tool reached for when an env var
|
||||
# isn't working — it must not throw on misconfiguration.
|
||||
# isn't working - it must not throw on misconfiguration.
|
||||
monkeypatch.setenv("MESHTASTIC_MCP_TCP_HOST", "host:notaport")
|
||||
with patch("meshtastic_mcp.devices.list_ports.comports", return_value=[]):
|
||||
ds = devices.list_devices(include_unknown=True)
|
||||
@@ -222,7 +222,7 @@ class TestDevicesTcpEntry:
|
||||
self, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
# `likely_meshtastic=False` keeps the bad TCP entry out of the
|
||||
# auto-select path — `resolve_port(None)` should still report
|
||||
# auto-select path - `resolve_port(None)` should still report
|
||||
# "no Meshtastic devices" rather than picking a broken endpoint.
|
||||
monkeypatch.setenv("MESHTASTIC_MCP_TCP_HOST", "host:notaport")
|
||||
with patch("meshtastic_mcp.devices.list_ports.comports", return_value=[]):
|
||||
@@ -274,7 +274,7 @@ class TestDevicesTcpEntry:
|
||||
ds = devices.list_devices(include_unknown=True)
|
||||
|
||||
assert ds, "expected at least the USB + TCP entries"
|
||||
# Real USB candidate must be at position 0 — it's likely_meshtastic.
|
||||
# Real USB candidate must be at position 0 - it's likely_meshtastic.
|
||||
assert ds[0]["port"] == "/dev/cu.usbmodem4201"
|
||||
assert ds[0]["likely_meshtastic"] is True
|
||||
# The malformed TCP entry exists but lands among the unlikely entries.
|
||||
@@ -287,7 +287,7 @@ class TestDevicesTcpEntry:
|
||||
self, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
# Conversely, a *valid* TCP env var should sort ahead of USB
|
||||
# candidates of equal likely_meshtastic rank — explicit env-var
|
||||
# candidates of equal likely_meshtastic rank - explicit env-var
|
||||
# configuration is a precedence signal.
|
||||
monkeypatch.setenv("MESHTASTIC_MCP_TCP_HOST", "localhost:4403")
|
||||
|
||||
@@ -375,7 +375,7 @@ class TestConnectRoutesTcp:
|
||||
with connection.connect(port="tcp://locktest:4403"):
|
||||
pass
|
||||
|
||||
# Lock should be released — a second connect attempt must not fail
|
||||
# Lock should be released - a second connect attempt must not fail
|
||||
# with "busy".
|
||||
with patch("meshtastic.tcp_interface.TCPInterface") as mock_tcp:
|
||||
mock_tcp.return_value.close.return_value = None
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Tests for the fake-NodeDB fixture pipeline (bin/gen-fake-nodedb-seed.py
|
||||
+ bin/seed-json-to-proto.py + mcp-server fixtures.push_fake_nodedb).
|
||||
|
||||
Lives under tests/unit/ because none of these touch real hardware — they
|
||||
Lives under tests/unit/ because none of these touch real hardware - they
|
||||
shell out to the bin/ scripts and decode the resulting protobufs in-process.
|
||||
"""
|
||||
|
||||
@@ -42,7 +42,7 @@ def _require_v25_bindings() -> None:
|
||||
)
|
||||
if "positions" not in NodeDatabase.DESCRIPTOR.fields_by_name:
|
||||
pytest.skip(
|
||||
"Loaded NodeDatabase predates v25 — run `./bin/regen-py-protos.sh`."
|
||||
"Loaded NodeDatabase predates v25 - run `./bin/regen-py-protos.sh`."
|
||||
)
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ def test_committed_seed_compiles_and_decodes(size: int, tmp_path: pathlib.Path)
|
||||
proto = tmp_path / "out.proto"
|
||||
jsonl = FIXTURES_DIR / f"seed_v25_{size:04d}.jsonl"
|
||||
if not jsonl.is_file():
|
||||
pytest.skip(f"{jsonl} not present — run ./bin/regen-fake-nodedbs.sh")
|
||||
pytest.skip(f"{jsonl} not present - run ./bin/regen-fake-nodedbs.sh")
|
||||
_run([sys.executable, str(COMPILE), "--in", str(jsonl), "--out", str(proto)])
|
||||
|
||||
db = NodeDatabase()
|
||||
@@ -199,7 +199,7 @@ def test_compile_freshens_timestamps(tmp_path: pathlib.Path) -> None:
|
||||
_require_v25_bindings()
|
||||
jsonl = FIXTURES_DIR / "seed_v25_0250.jsonl"
|
||||
if not jsonl.is_file():
|
||||
pytest.skip("250-node seed not present — run ./bin/regen-fake-nodedbs.sh")
|
||||
pytest.skip("250-node seed not present - run ./bin/regen-fake-nodedbs.sh")
|
||||
a = tmp_path / "a.proto"
|
||||
b = tmp_path / "b.proto"
|
||||
_run([sys.executable, str(COMPILE), "--in", str(jsonl), "--out", str(a)])
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Pin `InputEventCode` values to the firmware `input_broker_event` enum.
|
||||
|
||||
If this test fails, someone changed the firmware enum (or this Python
|
||||
mirror) and they must stay in sync — the admin RPC sends these as u8
|
||||
mirror) and they must stay in sync - the admin RPC sends these as u8
|
||||
wire values directly.
|
||||
|
||||
Also exercises `coerce_event_code` for the happy + error paths.
|
||||
|
||||
@@ -75,7 +75,7 @@ class TestParseLogLine:
|
||||
assert out["msg"] == "raw message body"
|
||||
|
||||
def test_bare_message(self) -> None:
|
||||
# LogRecord.message path — no level prefix at all.
|
||||
# LogRecord.message path - no level prefix at all.
|
||||
out = parse_log_line("just a bare message")
|
||||
assert "level" not in out or out.get("level") is None
|
||||
assert out["line"] == "just a bare message"
|
||||
@@ -155,7 +155,7 @@ class TestRecorderDebugHeapSynthesis:
|
||||
assert synth[-1]["fields"]["heap_total_bytes"] == 200000
|
||||
|
||||
def test_no_heap_no_synthesis(self, recorder: "Recorder") -> None:
|
||||
# Plain log line (no [heap N], no Heap status) — telemetry.jsonl
|
||||
# Plain log line (no [heap N], no Heap status) - telemetry.jsonl
|
||||
# should NOT gain a synth row.
|
||||
before = (recorder.base_dir / "telemetry.jsonl").read_text().count("\n")
|
||||
recorder._on_log_line("INFO | 00:00:00 1 [Main] just a message", _FakeIface())
|
||||
@@ -234,7 +234,7 @@ class TestSerialTap:
|
||||
def test_serial_line_handler_swallows_exceptions(
|
||||
self, recorder: "Recorder"
|
||||
) -> None:
|
||||
# Hostile input — should not raise.
|
||||
# Hostile input - should not raise.
|
||||
recorder._on_serial_line(None, port="/dev/cu.tap") # type: ignore[arg-type]
|
||||
recorder._on_serial_line(b"\x00\x01\x02\x03", port="/dev/cu.tap") # type: ignore[arg-type]
|
||||
# Survived.
|
||||
@@ -320,11 +320,11 @@ class TestRecorderWrites:
|
||||
recorder._on_log_line("INFO | 12:34:56 99 [T] hi", _FakeIface())
|
||||
path = recorder.base_dir / "logs.jsonl"
|
||||
rows = [json.loads(line) for line in path.read_text().splitlines() if line]
|
||||
# First row is recorder_start_event mirror? No — that's events.jsonl only.
|
||||
# First row is recorder_start_event mirror? No - that's events.jsonl only.
|
||||
assert any(r.get("level") == "INFO" and r.get("tag") == "T" for r in rows)
|
||||
|
||||
def test_telemetry_recorded_and_packet_double(self, recorder: Recorder) -> None:
|
||||
# _on_telemetry alone — only telemetry.jsonl
|
||||
# _on_telemetry alone - only telemetry.jsonl
|
||||
recorder._on_telemetry(
|
||||
{
|
||||
"fromId": "!abc",
|
||||
@@ -367,13 +367,13 @@ class TestRecorderWrites:
|
||||
assert "kept" in post_resume
|
||||
|
||||
def test_pubsub_handler_swallows_exceptions(self, recorder: Recorder) -> None:
|
||||
# If the writer dies, the pubsub callback must NOT raise — that
|
||||
# If the writer dies, the pubsub callback must NOT raise - that
|
||||
# would crash the meshtastic receive thread.
|
||||
bad_packet = object() # not a dict
|
||||
recorder._on_receive(bad_packet, _FakeIface()) # type: ignore[arg-type]
|
||||
recorder._on_telemetry(bad_packet, _FakeIface()) # type: ignore[arg-type]
|
||||
recorder._on_log_line(None, _FakeIface()) # type: ignore[arg-type]
|
||||
# No assertion needed — survival is the test.
|
||||
# No assertion needed - survival is the test.
|
||||
|
||||
|
||||
# -- log_query read side ---------------------------------------------
|
||||
|
||||
@@ -113,7 +113,7 @@ def test_owner_names_included_when_provided() -> None:
|
||||
|
||||
def test_psk_seed_isolation_across_ci_runs() -> None:
|
||||
"""The core claim: two test labs running concurrently with different
|
||||
session seeds produce different PSKs — their meshes cannot decode each
|
||||
session seeds produce different PSKs - their meshes cannot decode each
|
||||
other's traffic."""
|
||||
lab_a = userprefs.build_testing_profile(psk_seed="lab-A-nightly")
|
||||
lab_b = userprefs.build_testing_profile(psk_seed="lab-B-nightly")
|
||||
|
||||
@@ -5,9 +5,9 @@ new hub-descriptor fields (e.g. the `, ppps` marker). The parser uses loose
|
||||
regexes to tolerate additions; this test keeps us honest.
|
||||
|
||||
Samples captured from:
|
||||
- v2.6.0 on macOS (Homebrew) — two USB2 hubs, one populated with an
|
||||
- v2.6.0 on macOS (Homebrew) - two USB2 hubs, one populated with an
|
||||
nRF52 and a CP2102, plus chained USB3 hubs.
|
||||
- v2.5.0 on Linux (hypothetical — reconstructed from the project README).
|
||||
- v2.5.0 on Linux (hypothetical - reconstructed from the project README).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""Pin the `Screen: frame N/M name=X reason=Y` regex + FrameEvent dataclass.
|
||||
|
||||
The firmware-side format lives in `src/graphics/Screen.cpp::logFrameChange`;
|
||||
if the format string changes, this test — and the parser in
|
||||
`tests/ui/_screen_log.py` — have to be updated together.
|
||||
if the format string changes, this test - and the parser in
|
||||
`tests/ui/_screen_log.py` - have to be updated together.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -23,7 +23,7 @@ class TestFrameEventParse:
|
||||
|
||||
def test_with_log_prefix(self) -> None:
|
||||
"""Log lines may be preamble-wrapped by the firmware LOG_INFO macro
|
||||
(timestamp, severity, etc.) — the regex uses .search() not .match()
|
||||
(timestamp, severity, etc.) - the regex uses .search() not .match()
|
||||
so prefixes are fine."""
|
||||
raw = "[INFO] 00:12:34 567 Screen: frame 4/12 name=nodelist_nodes reason=fn_f3 "
|
||||
evt = FrameEvent.parse(raw)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
write, and the `temporary_overrides` context manager's byte-for-byte restore.
|
||||
|
||||
None of these require hardware. They validate the contract that the flash/
|
||||
testing-profile tools rely on — if these fail, the provisioning tier will
|
||||
testing-profile tools rely on - if these fail, the provisioning tier will
|
||||
produce confusing mismatches.
|
||||
"""
|
||||
|
||||
@@ -63,7 +63,7 @@ def test_infer_type_matches_platformio_custom_py() -> None:
|
||||
|
||||
def test_temporary_overrides_restores_byte_for_byte(sample_jsonc: Path) -> None:
|
||||
"""The context manager MUST leave the file bit-identical on exit, even on
|
||||
exception — this is the safety guarantee build/flash tools rely on."""
|
||||
exception - this is the safety guarantee build/flash tools rely on."""
|
||||
original = sample_jsonc.read_bytes()
|
||||
|
||||
with userprefs.temporary_overrides({"USERPREFS_CHANNEL_0_NAME": "OverrideTest"}):
|
||||
@@ -104,7 +104,7 @@ def test_build_manifest_surfaces_all_keys(sample_jsonc: Path) -> None:
|
||||
"""Manifest should union the jsonc set with firmware-src consumers.
|
||||
|
||||
In the sample tmpdir there's no `src/` so `consumed_by` is empty for all
|
||||
entries; that's fine — the manifest still lists every jsonc key.
|
||||
entries; that's fine - the manifest still lists every jsonc key.
|
||||
"""
|
||||
manifest = userprefs.build_manifest()
|
||||
keys = {e["key"] for e in manifest["entries"]}
|
||||
|
||||
Reference in New Issue
Block a user