"""Unit tests for SCPI command parsing.""" import pytest from py_dvt_ate.instruments.scpi import SCPICommand, SCPIParser class TestSCPICommand: """Tests for the SCPICommand dataclass.""" def test_creation(self) -> None: """Test SCPICommand can be created with valid values.""" cmd = SCPICommand( header="VOLT", arguments=["3.3"], is_query=False, ) assert cmd.header == "VOLT" assert cmd.arguments == ["3.3"] assert cmd.is_query is False def test_keyword_for_command(self) -> None: """Test keyword property for regular command.""" cmd = SCPICommand(header="VOLT", arguments=["3.3"], is_query=False) assert cmd.keyword == "VOLT" def test_keyword_for_query(self) -> None: """Test keyword property strips '?' from query.""" cmd = SCPICommand(header="VOLT?", arguments=[], is_query=True) assert cmd.keyword == "VOLT" def test_keyword_for_nested_command(self) -> None: """Test keyword property for nested SCPI command.""" cmd = SCPICommand(header="TEMP:SETPOINT?", arguments=[], is_query=True) assert cmd.keyword == "TEMP:SETPOINT" class TestSCPIParser: """Tests for the SCPIParser class.""" @pytest.fixture def parser(self) -> SCPIParser: """Create parser instance for tests.""" return SCPIParser() def test_parse_simple_query(self, parser: SCPIParser) -> None: """Test parsing simple query command.""" cmd = parser.parse("*IDN?") assert cmd.header == "*IDN?" assert cmd.arguments == [] assert cmd.is_query is True assert cmd.keyword == "*IDN" def test_parse_simple_command(self, parser: SCPIParser) -> None: """Test parsing simple command without arguments.""" cmd = parser.parse("*RST") assert cmd.header == "*RST" assert cmd.arguments == [] assert cmd.is_query is False assert cmd.keyword == "*RST" def test_parse_command_with_single_argument(self, parser: SCPIParser) -> None: """Test parsing command with single numeric argument.""" cmd = parser.parse("VOLT 3.3") assert cmd.header == "VOLT" assert cmd.arguments == ["3.3"] assert cmd.is_query is False def test_parse_command_with_multiple_arguments(self, parser: SCPIParser) -> None: """Test parsing command with comma-separated arguments.""" cmd = parser.parse("CONF:VOLT:DC 10,0.001") assert cmd.header == "CONF:VOLT:DC" assert cmd.arguments == ["10", "0.001"] assert cmd.is_query is False def test_parse_nested_scpi_command(self, parser: SCPIParser) -> None: """Test parsing nested SCPI command hierarchy.""" cmd = parser.parse("TEMP:SETPOINT 85.0") assert cmd.header == "TEMP:SETPOINT" assert cmd.arguments == ["85.0"] assert cmd.is_query is False assert cmd.keyword == "TEMP:SETPOINT" def test_parse_nested_scpi_query(self, parser: SCPIParser) -> None: """Test parsing nested SCPI query.""" cmd = parser.parse("TEMP:SETPOINT?") assert cmd.header == "TEMP:SETPOINT?" assert cmd.arguments == [] assert cmd.is_query is True def test_parse_ieee_common_commands(self, parser: SCPIParser) -> None: """Test parsing IEEE 488.2 common commands.""" # Identity query cmd = parser.parse("*IDN?") assert cmd.is_query is True assert cmd.keyword == "*IDN" # Reset cmd = parser.parse("*RST") assert cmd.is_query is False assert cmd.keyword == "*RST" # Clear status cmd = parser.parse("*CLS") assert cmd.is_query is False assert cmd.keyword == "*CLS" # Operation complete query cmd = parser.parse("*OPC?") assert cmd.is_query is True assert cmd.keyword == "*OPC" def test_parse_strips_whitespace(self, parser: SCPIParser) -> None: """Test parser strips leading and trailing whitespace.""" cmd = parser.parse(" VOLT 3.3 ") assert cmd.header == "VOLT" assert cmd.arguments == ["3.3"] def test_parse_strips_argument_whitespace(self, parser: SCPIParser) -> None: """Test parser strips whitespace from arguments.""" cmd = parser.parse("CONF:VOLT:DC 10 , 0.001 ") assert cmd.arguments == ["10", "0.001"] def test_parse_empty_string(self, parser: SCPIParser) -> None: """Test parsing empty string returns empty command.""" cmd = parser.parse("") assert cmd.header == "" assert cmd.arguments == [] assert cmd.is_query is False def test_parse_whitespace_only(self, parser: SCPIParser) -> None: """Test parsing whitespace-only string returns empty command.""" cmd = parser.parse(" ") assert cmd.header == "" assert cmd.arguments == [] assert cmd.is_query is False def test_parse_output_on_off(self, parser: SCPIParser) -> None: """Test parsing output enable/disable commands.""" cmd_on = parser.parse("OUTP ON") assert cmd_on.arguments == ["ON"] cmd_off = parser.parse("OUTP OFF") assert cmd_off.arguments == ["OFF"] cmd_1 = parser.parse("OUTP 1") assert cmd_1.arguments == ["1"] cmd_0 = parser.parse("OUTP 0") assert cmd_0.arguments == ["0"] def test_parse_channel_select(self, parser: SCPIParser) -> None: """Test parsing channel selection commands.""" cmd = parser.parse("INST:SEL CH1") assert cmd.header == "INST:SEL" assert cmd.arguments == ["CH1"] def test_parse_measurement_query(self, parser: SCPIParser) -> None: """Test parsing measurement query commands.""" cmd = parser.parse("MEAS:VOLT:DC?") assert cmd.header == "MEAS:VOLT:DC?" assert cmd.is_query is True assert cmd.keyword == "MEAS:VOLT:DC" def test_parse_measurement_with_range(self, parser: SCPIParser) -> None: """Test parsing measurement query with range argument.""" cmd = parser.parse("MEAS:VOLT:DC? AUTO") assert cmd.header == "MEAS:VOLT:DC?" assert cmd.arguments == ["AUTO"] assert cmd.is_query is True def test_parse_system_error_query(self, parser: SCPIParser) -> None: """Test parsing system error query.""" cmd = parser.parse("SYST:ERR?") assert cmd.header == "SYST:ERR?" assert cmd.is_query is True assert cmd.keyword == "SYST:ERR" def test_parse_nplc_setting(self, parser: SCPIParser) -> None: """Test parsing NPLC (integration time) command.""" cmd = parser.parse("SENS:VOLT:DC:NPLC 10") assert cmd.header == "SENS:VOLT:DC:NPLC" assert cmd.arguments == ["10"] assert cmd.is_query is False