Replace progpib.py stub with a proper installable package
Builds a modern, testable API for the Prologix GPIB-ETHERNET controller (GPIB-USB structurally supported but untested, no hardware available): Transport abstraction (Ethernet now, serial later), GpibController for the full "++" command set, a clean-room netfinder discovery client that fixes a real chr()/struct-format bug present in vendortools/nfutil.py, and a CLI (discover/config/info/terminal). vendortools/, pty-gpib-emulator/, sampledata.txt and the manual PDF are kept untouched as reference material. Depends on the sibling bits package (editable, not yet pinned -- see its own commit) for MAC formatting and IEEE-488.2 status-byte bit access. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
84
tests/test_controller.py
Normal file
84
tests/test_controller.py
Normal file
@@ -0,0 +1,84 @@
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from bits import Bit
|
||||
|
||||
from progpib.controller import GpibController
|
||||
from progpib.exceptions import CommandError
|
||||
|
||||
|
||||
def _wait_until(condition, timeout=2.0, interval=0.02):
|
||||
deadline = time.monotonic() + timeout
|
||||
while time.monotonic() < deadline:
|
||||
if condition():
|
||||
return True
|
||||
time.sleep(interval)
|
||||
return condition()
|
||||
|
||||
|
||||
def test_mode_property_roundtrip(fake_gpib_server):
|
||||
server, tcp_server = fake_gpib_server
|
||||
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
||||
ctrl.mode = 1
|
||||
assert ctrl.mode == 1
|
||||
ctrl.mode = 0
|
||||
assert ctrl.mode == 0
|
||||
|
||||
|
||||
def test_addr_property_roundtrip_as_tuple(fake_gpib_server):
|
||||
server, tcp_server = fake_gpib_server
|
||||
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
||||
ctrl.addr = (5, 96)
|
||||
assert ctrl.addr == (5, 96)
|
||||
ctrl.addr = 12
|
||||
assert ctrl.addr == 12
|
||||
|
||||
|
||||
def test_ver_returns_server_version(fake_gpib_server):
|
||||
server, tcp_server = fake_gpib_server
|
||||
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
||||
assert ctrl.ver() == server.version
|
||||
|
||||
|
||||
def test_write_escapes_special_bytes_on_the_wire(fake_gpib_server):
|
||||
server, tcp_server = fake_gpib_server
|
||||
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
||||
ctrl.write("*IDN?\r\n+test")
|
||||
expected = b"*IDN?\x1b\r\x1b\n\x1b+test\n"
|
||||
assert _wait_until(lambda: bytes(server.raw_received) == expected)
|
||||
|
||||
|
||||
def test_read_tmo_ms_range_validation_without_network(fake_gpib_server):
|
||||
server, tcp_server = fake_gpib_server
|
||||
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
||||
with pytest.raises(ValueError):
|
||||
ctrl.read_tmo_ms = 5000
|
||||
# unchanged: the invalid value was never sent
|
||||
assert ctrl.read_tmo_ms == 500
|
||||
|
||||
|
||||
def test_status_and_lon_raise_in_controller_mode(fake_gpib_server):
|
||||
server, tcp_server = fake_gpib_server
|
||||
server.state["mode"] = "1" # CONTROLLER
|
||||
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
||||
with pytest.raises(CommandError):
|
||||
_ = ctrl.status
|
||||
with pytest.raises(CommandError):
|
||||
_ = ctrl.lon
|
||||
|
||||
|
||||
def test_status_and_spoll_return_bits_with_rqs_at_index_6(fake_gpib_server):
|
||||
server, tcp_server = fake_gpib_server
|
||||
server.state["mode"] = "0" # DEVICE
|
||||
server.state["status"] = "72" # 0x48: RQS (bit 6) and bit 3 set
|
||||
server.spoll_response = 72
|
||||
|
||||
with GpibController.ethernet(tcp_server.host, tcp_server.port) as ctrl:
|
||||
status = ctrl.status
|
||||
assert int(status) == 72
|
||||
assert status[6] == Bit(1)
|
||||
assert status[5] == Bit(0)
|
||||
|
||||
result = ctrl.spoll()
|
||||
assert int(result) == 72
|
||||
assert result[6] == Bit(1)
|
||||
Reference in New Issue
Block a user