Skip to content

Commit 39ef2f1

Browse files
authored
Add docstrings and some more static tests (#163)
* Add docstrings * Additional static tests. * fix tests * Update __init__.py * Update test_api.py
1 parent 3b7c042 commit 39ef2f1

File tree

13 files changed

+234
-17
lines changed

13 files changed

+234
-17
lines changed

.pre-commit-config.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,20 @@ repos:
1818
- --quiet
1919
- --safe
2020

21-
- repo: https://github.com/pycqa/flake8
21+
- repo: https://github.com/PyCQA/flake8
2222
rev: 6.0.0
2323
hooks:
2424
- id: flake8
2525
additional_dependencies:
26+
- flake8-docstrings==1.5.0
27+
- pydocstyle==5.1.1
2628
- Flake8-pyproject==1.2.3
29+
- flake8-bugbear==23.1.20
30+
- flake8-comprehensions==3.10.1
31+
- flake8_2020==1.7.0
32+
- mccabe==0.7.0
33+
- pycodestyle==2.10.0
34+
- pyflakes==3.0.1
2735

2836
- repo: https://github.com/PyCQA/isort
2937
rev: 5.12.0

tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Tests for zigpy_xbee."""

tests/test_api.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Tests for API."""
2+
13
import asyncio
24
import logging
35

@@ -19,18 +21,21 @@
1921

2022
@pytest.fixture
2123
def api():
24+
"""Sample XBee API fixture."""
2225
api = xbee_api.XBee(DEVICE_CONFIG)
2326
api._uart = mock.MagicMock()
2427
return api
2528

2629

2730
async def test_connect(monkeypatch):
31+
"""Test connect."""
2832
api = xbee_api.XBee(DEVICE_CONFIG)
2933
monkeypatch.setattr(uart, "connect", mock.AsyncMock())
3034
await api.connect()
3135

3236

3337
def test_close(api):
38+
"""Test connection close."""
3439
uart = api._uart
3540
conn_lost_task = mock.MagicMock()
3641
api._conn_lost_task = conn_lost_task
@@ -44,6 +49,7 @@ def test_close(api):
4449

4550

4651
def test_commands():
52+
"""Test command requests and command responses description."""
4753
import string
4854

4955
anum = string.ascii_letters + string.digits + "_"
@@ -60,6 +66,8 @@ def test_commands():
6066

6167

6268
async def test_command(api):
69+
"""Test AT commands."""
70+
6371
def mock_api_frame(name, *args):
6472
c = xbee_api.COMMAND_REQUESTS[name]
6573
return mock.sentinel.api_frame_data, c[2]
@@ -97,14 +105,15 @@ def mock_api_frame(name, *args):
97105

98106

99107
async def test_command_not_connected(api):
108+
"""Test AT command while disconnected to the device."""
100109
api._uart = None
101110

102111
def mock_api_frame(name, *args):
103112
return mock.sentinel.api_frame_data, api._seq
104113

105114
api._api_frame = mock.MagicMock(side_effect=mock_api_frame)
106115

107-
for cmd, cmd_opts in xbee_api.COMMAND_REQUESTS.items():
116+
for cmd, _cmd_opts in xbee_api.COMMAND_REQUESTS.items():
108117
with pytest.raises(zigpy.exceptions.APIException):
109118
await api._command(cmd, mock.sentinel.cmd_data)
110119
assert api._api_frame.call_count == 0
@@ -115,6 +124,7 @@ async def _test_at_or_queued_at_command(api, cmd, monkeypatch, do_reply=True):
115124
monkeypatch.setattr(
116125
t, "serialize", mock.MagicMock(return_value=mock.sentinel.serialize)
117126
)
127+
"""Call api._at_command() or api._queued_at() with every possible command."""
118128

119129
def mock_command(name, *args):
120130
rsp = xbee_api.COMMAND_REQUESTS[name][2]
@@ -141,24 +151,28 @@ def mock_command(name, *args):
141151

142152

143153
async def test_at_command(api, monkeypatch):
154+
"""Test api._at_command."""
144155
await _test_at_or_queued_at_command(api, api._at_command, monkeypatch)
145156

146157

147158
async def test_at_command_no_response(api, monkeypatch):
159+
"""Test api._at_command with no response."""
148160
with pytest.raises(asyncio.TimeoutError):
149161
await _test_at_or_queued_at_command(
150162
api, api._at_command, monkeypatch, do_reply=False
151163
)
152164

153165

154166
async def test_queued_at_command(api, monkeypatch):
167+
"""Test api._queued_at."""
155168
await _test_at_or_queued_at_command(api, api._queued_at, monkeypatch)
156169

157170

158171
async def _test_remote_at_command(api, monkeypatch, do_reply=True):
159172
monkeypatch.setattr(
160173
t, "serialize", mock.MagicMock(return_value=mock.sentinel.serialize)
161174
)
175+
"""Call api._remote_at_command()."""
162176

163177
def mock_command(name, *args):
164178
rsp = xbee_api.COMMAND_REQUESTS[name][2]
@@ -194,16 +208,19 @@ def mock_command(name, *args):
194208

195209

196210
async def test_remote_at_cmd(api, monkeypatch):
211+
"""Test remote AT command."""
197212
await _test_remote_at_command(api, monkeypatch)
198213

199214

200215
async def test_remote_at_cmd_no_rsp(api, monkeypatch):
216+
"""Test remote AT command with no response."""
201217
monkeypatch.setattr(xbee_api, "REMOTE_AT_COMMAND_TIMEOUT", 0.1)
202218
with pytest.raises(asyncio.TimeoutError):
203219
await _test_remote_at_command(api, monkeypatch, do_reply=False)
204220

205221

206222
def test_api_frame(api):
223+
"""Test api._api_frame."""
207224
ieee = t.EUI64([t.uint8_t(a) for a in range(0, 8)])
208225
for cmd_name, cmd_opts in xbee_api.COMMAND_REQUESTS.items():
209226
cmd_id, schema, repl = cmd_opts
@@ -215,6 +232,7 @@ def test_api_frame(api):
215232

216233

217234
def test_frame_received(api, monkeypatch):
235+
"""Test api.frame_received()."""
218236
monkeypatch.setattr(
219237
t,
220238
"deserialize",
@@ -255,6 +273,7 @@ def test_frame_received(api, monkeypatch):
255273

256274

257275
def test_frame_received_no_handler(api, monkeypatch):
276+
"""Test frame received with no handler defined."""
258277
monkeypatch.setattr(
259278
t, "deserialize", mock.MagicMock(return_value=(b"deserialized data", b""))
260279
)
@@ -275,6 +294,7 @@ def test_frame_received_no_handler(api, monkeypatch):
275294

276295

277296
def _handle_at_response(api, tsn, status, at_response=b""):
297+
"""Call api._handle_at_response."""
278298
data = (tsn, b"AI", status, at_response)
279299
response = asyncio.Future()
280300
api._awaiting[tsn] = (response,)
@@ -283,6 +303,7 @@ def _handle_at_response(api, tsn, status, at_response=b""):
283303

284304

285305
def test_handle_at_response_none(api):
306+
"""Test AT successful response with no value."""
286307
tsn = 123
287308
fut = _handle_at_response(api, tsn, 0)
288309
assert fut.done() is True
@@ -291,6 +312,7 @@ def test_handle_at_response_none(api):
291312

292313

293314
def test_handle_at_response_data(api):
315+
"""Test AT successful response with data."""
294316
tsn = 123
295317
status, response = 0, 0x23
296318
fut = _handle_at_response(api, tsn, status, [response])
@@ -300,6 +322,7 @@ def test_handle_at_response_data(api):
300322

301323

302324
def test_handle_at_response_error(api):
325+
"""Test AT unsuccessful response."""
303326
tsn = 123
304327
status, response = 1, 0x23
305328
fut = _handle_at_response(api, tsn, status, [response])
@@ -308,6 +331,7 @@ def test_handle_at_response_error(api):
308331

309332

310333
def test_handle_at_response_undef_error(api):
334+
"""Test AT unsuccessful response with undefined error."""
311335
tsn = 123
312336
status, response = 0xEE, 0x23
313337
fut = _handle_at_response(api, tsn, status, [response])
@@ -316,6 +340,7 @@ def test_handle_at_response_undef_error(api):
316340

317341

318342
def test_handle_remote_at_rsp(api):
343+
"""Test handling the response."""
319344
api._handle_at_response = mock.MagicMock()
320345
s = mock.sentinel
321346
api._handle_remote_at_response(s.frame_id, s.ieee, s.nwk, s.cmd, s.status, s.data)
@@ -327,13 +352,15 @@ def test_handle_remote_at_rsp(api):
327352

328353

329354
def _send_modem_event(api, event):
355+
"""Call api._handle_modem_status()."""
330356
api._app = mock.MagicMock(spec=ControllerApplication)
331357
api._handle_modem_status(event)
332358
assert api._app.handle_modem_status.call_count == 1
333359
assert api._app.handle_modem_status.call_args[0][0] == event
334360

335361

336362
def test_handle_modem_status(api):
363+
"""Test api._handle_modem_status()."""
337364
api._running.clear()
338365
api._reset.set()
339366
_send_modem_event(api, xbee_t.ModemStatus.COORDINATOR_STARTED)
@@ -354,6 +381,7 @@ def test_handle_modem_status(api):
354381

355382

356383
def test_handle_explicit_rx_indicator(api):
384+
"""Test receiving explicit_rx_indicator frame."""
357385
s = mock.sentinel
358386
data = [
359387
s.src_ieee,
@@ -372,6 +400,7 @@ def test_handle_explicit_rx_indicator(api):
372400

373401

374402
def _handle_tx_status(api, status, wrong_frame_id=False):
403+
"""Call api._handle_tx_status."""
375404
status = xbee_t.TXStatus(status)
376405
frame_id = 0x12
377406
send_fut = mock.MagicMock(spec=asyncio.Future)
@@ -386,27 +415,31 @@ def _handle_tx_status(api, status, wrong_frame_id=False):
386415

387416

388417
def test_handle_tx_status_success(api):
418+
"""Test handling successful TX Status."""
389419
fut = _handle_tx_status(api, xbee_t.TXStatus.SUCCESS)
390420
assert len(api._awaiting) == 0
391421
assert fut.set_result.call_count == 1
392422
assert fut.set_exception.call_count == 0
393423

394424

395425
def test_handle_tx_status_except(api):
426+
"""Test exceptional TXStatus."""
396427
fut = _handle_tx_status(api, xbee_t.TXStatus.ADDRESS_NOT_FOUND)
397428
assert len(api._awaiting) == 0
398429
assert fut.set_result.call_count == 0
399430
assert fut.set_exception.call_count == 1
400431

401432

402433
def test_handle_tx_status_unexpected(api):
434+
"""Test TX status reply on unexpected frame."""
403435
fut = _handle_tx_status(api, 1, wrong_frame_id=True)
404436
assert len(api._awaiting) == 1
405437
assert fut.set_result.call_count == 0
406438
assert fut.set_exception.call_count == 0
407439

408440

409441
def test_handle_tx_status_duplicate(api):
442+
"""Test TX status duplicate reply."""
410443
status = xbee_t.TXStatus.SUCCESS
411444
frame_id = 0x12
412445
send_fut = mock.MagicMock(spec=asyncio.Future)
@@ -420,6 +453,7 @@ def test_handle_tx_status_duplicate(api):
420453

421454

422455
def test_handle_registration_status(api):
456+
"""Test device registration status."""
423457
frame_id = 0x12
424458
status = xbee_t.RegistrationStatus.SUCCESS
425459
fut = asyncio.Future()
@@ -440,6 +474,7 @@ def test_handle_registration_status(api):
440474

441475

442476
async def test_command_mode_at_cmd(api):
477+
"""Test AT in command mode."""
443478
command = "+++"
444479

445480
def cmd_mode_send(cmd):
@@ -452,6 +487,7 @@ def cmd_mode_send(cmd):
452487

453488

454489
async def test_command_mode_at_cmd_timeout(api):
490+
"""Test AT in command mode with timeout."""
455491
command = "+++"
456492

457493
api._uart.command_mode_send = mock.MagicMock()
@@ -461,6 +497,7 @@ async def test_command_mode_at_cmd_timeout(api):
461497

462498

463499
def test_handle_command_mode_rsp(api):
500+
"""Test command mode response."""
464501
api._cmd_mode_future = None
465502
data = "OK"
466503
api.handle_command_mode_rsp(data)
@@ -483,13 +520,15 @@ def test_handle_command_mode_rsp(api):
483520

484521

485522
async def test_enter_at_command_mode(api):
523+
"""Test switching to command mode."""
486524
api.command_mode_at_cmd = mock.AsyncMock(return_value=mock.sentinel.at_response)
487525

488526
res = await api.enter_at_command_mode()
489527
assert res == mock.sentinel.at_response
490528

491529

492530
async def test_api_mode_at_commands(api):
531+
"""Test AT in API mode."""
493532
api.command_mode_at_cmd = mock.AsyncMock(return_value=mock.sentinel.api_mode)
494533

495534
res = await api.api_mode_at_commands(57600)
@@ -506,6 +545,7 @@ async def mock_at_cmd(cmd):
506545

507546

508547
async def test_init_api_mode(api, monkeypatch):
548+
"""Test init the API mode."""
509549
monkeypatch.setattr(api._uart, "baudrate", 57600)
510550
api.enter_at_command_mode = mock.AsyncMock(return_value=True)
511551

@@ -534,22 +574,26 @@ async def enter_at_mode():
534574

535575

536576
def test_set_application(api):
577+
"""Test setting the application."""
537578
api.set_application(mock.sentinel.app)
538579
assert api._app == mock.sentinel.app
539580

540581

541582
def test_handle_route_record_indicator(api):
583+
"""Test api._handle_route_record_indicator()."""
542584
s = mock.sentinel
543585
api._handle_route_record_indicator(s.ieee, s.src, s.rx_opts, s.hops)
544586

545587

546588
def test_handle_many_to_one_rri(api):
589+
"""Test api._handle_many_to_one_rri()."""
547590
ieee = t.EUI64([t.uint8_t(a) for a in range(0, 8)])
548591
nwk = 0x1234
549592
api._handle_many_to_one_rri(ieee, nwk, 0)
550593

551594

552595
async def test_reconnect_multiple_disconnects(monkeypatch, caplog):
596+
"""Test reconnect with multiple disconnects."""
553597
api = xbee_api.XBee(DEVICE_CONFIG)
554598
connect_mock = mock.AsyncMock(return_value=True)
555599
monkeypatch.setattr(uart, "connect", connect_mock)
@@ -570,6 +614,7 @@ async def test_reconnect_multiple_disconnects(monkeypatch, caplog):
570614

571615

572616
async def test_reconnect_multiple_attempts(monkeypatch, caplog):
617+
"""Test reconnect with multiple attempts."""
573618
api = xbee_api.XBee(DEVICE_CONFIG)
574619
connect_mock = mock.AsyncMock(return_value=True)
575620
monkeypatch.setattr(uart, "connect", connect_mock)

0 commit comments

Comments
 (0)