"""Reading the environment, and refusing a setting the node cannot use.""" import pytest from dora_ulite6.config import Config, env_float, env_int from dora_ulite6.effectors import ( EFFECTORS, GripperEffector, NoEffector, VacuumEffector, get_effector, ) from dora_ulite6.errors import EffectorUnsupportedError @pytest.fixture(autouse=True) def clean_env(monkeypatch): """Run every test against a bare environment, whatever the shell set.""" for name in ("ROBOT_IP", "TOOL_TYPE", "TOOL_OFFSET_MM", "INIT_MODE", "INIT_Z", "DEFAULT_SPEED"): monkeypatch.delenv(name, raising=False) def test_the_defaults_need_no_environment(): config = Config.from_env() assert config.robot_ip == "192.168.1.192" assert isinstance(config.effector, NoEffector) assert config.tool_offset_mm == 0.0 assert config.init_mode == "none" def test_the_tool_offset_is_the_tools_own_plus_the_extra(monkeypatch): monkeypatch.setenv("TOOL_TYPE", "vacuum") monkeypatch.setenv("TOOL_OFFSET_MM", "4.5") config = Config.from_env() assert isinstance(config.effector, VacuumEffector) assert config.tool_offset_mm == pytest.approx(VacuumEffector.offset_mm + 4.5) def test_an_unknown_tool_is_refused_at_startup(monkeypatch): monkeypatch.setenv("TOOL_TYPE", "magnet") with pytest.raises(ValueError, match="vacuum"): Config.from_env() def test_an_unknown_init_mode_is_refused_at_startup(monkeypatch): # Caught here rather than at the first motion, so the node never joins the # dataflow with a startup move nobody can name. monkeypatch.setenv("INIT_MODE", "somewhere") with pytest.raises(ValueError, match="INIT_MODE"): Config.from_env() def test_init_pose_components_are_read(monkeypatch): monkeypatch.setenv("INIT_MODE", "pose") monkeypatch.setenv("INIT_Z", "180") assert Config.from_env().init_pose.z == 180.0 @pytest.mark.parametrize("value", ["", " "]) def test_a_blank_variable_falls_back_to_the_default(monkeypatch, value): monkeypatch.setenv("DEFAULT_SPEED", value) assert env_float("DEFAULT_SPEED", 30.0) == 30.0 def test_a_number_that_is_not_one_names_itself(monkeypatch): monkeypatch.setenv("PATH_SAMPLES", "four") with pytest.raises(ValueError, match="PATH_SAMPLES"): env_int("PATH_SAMPLES", 4) def test_a_bare_flange_refuses_to_grasp(): with pytest.raises(EffectorUnsupportedError): NoEffector().attach(object()) def test_an_effector_is_refused_by_a_driver_that_cannot_switch_it(): class ArmWithNoTools: pass with pytest.raises(EffectorUnsupportedError, match="set_vacuum"): VacuumEffector().verify(ArmWithNoTools()) def test_each_effector_switches_the_driver_method_it_declares(): switched = [] class Arm: def set_gripper(self, closed): switched.append(closed) arm = Arm() effector = get_effector("gripper") effector.verify(arm) effector.attach(arm) effector.detach(arm) assert isinstance(effector, GripperEffector) assert switched == [True, False] def test_every_registered_effector_declares_a_reach(): assert all(effector.offset_mm >= 0 for effector in EFFECTORS.values())