fix(lf): identify_lf fails clearly on a raw async device (not "coroutine has no len")

capture drives the device synchronously (as Proxmark3.sync()'s proxy exposes it). Passing a
bare async Proxmark3() — whose methods return un-awaited coroutines, and which isn't even
connected — blew up deep in the demod with "object of type 'coroutine' has no len()". Now
identify_lf detects a coroutine-function device up front and raises an actionable TypeError
pointing at Proxmark3.sync().

The mock-based tests returned plain values, so they never exercised the async method shape;
added a test using a real coroutine function that reproduces and guards it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
michael
2026-07-14 20:58:30 -07:00
parent e57e6ed268
commit e82b94a490
2 changed files with 25 additions and 0 deletions

View File

@@ -363,6 +363,20 @@ class TestIdentifyLF:
def test_no_device(self):
assert identify_lf(None) is None
def test_rejects_async_device(self):
# a raw async Proxmark3() exposes coroutine-function methods — must fail with a clear
# message pointing at Proxmark3.sync(), not blow up deep in the demod on an un-awaited
# coroutine (the MagicMock tests couldn't catch this since mocks return plain values)
dev = MagicMock()
async def _aread(*a, **k):
return {}
dev.lf.read = _aread
try:
identify_lf(dev)
assert False, "expected TypeError for an async device"
except TypeError as e:
assert "sync" in str(e).lower()
class TestCaptureValidation:
def test_looks_like_samples_rejects_memory(self):