from engine.gamepad import ( AXIS_LEFT_TRIGGER, AXIS_LEFT_X, AXIS_RIGHT_TRIGGER, DEFAULT_GAMEPAD_BINDINGS, GamepadBindings, GamepadState, apply_deadzone, ) # --- apply_deadzone --------------------------------------------------------------------------- def test_deadzone_zeroes_small_values(): assert apply_deadzone(0.05) == 0.0 assert apply_deadzone(-0.1) == 0.0 def test_deadzone_passes_through_large_values(): assert apply_deadzone(0.5) == 0.5 assert apply_deadzone(-0.9) == -0.9 def test_deadzone_respects_custom_threshold(): assert apply_deadzone(0.3, deadzone=0.5) == 0.0 assert apply_deadzone(0.6, deadzone=0.5) == 0.6 # --- GamepadState ------------------------------------------------------------------------------ def test_axis_out_of_range_defaults_to_zero(): state = GamepadState(axes=[0.1, 0.2]) assert state.axis(AXIS_LEFT_X) == 0.1 assert state.axis(5) == 0.0 def test_digital_buttons_includes_pressed_real_buttons(): state = GamepadState(buttons={"gp_a": True, "gp_b": False}) assert state.digital_buttons() == {"gp_a"} def test_digital_buttons_thresholds_triggers_into_pseudo_buttons(): axes = [0.0] * 6 axes[AXIS_LEFT_TRIGGER] = 0.9 axes[AXIS_RIGHT_TRIGGER] = 0.1 state = GamepadState(axes=axes) assert state.digital_buttons() == {"gp_left_trigger"} def test_digital_buttons_combines_real_and_trigger_buttons(): axes = [0.0] * 6 axes[AXIS_RIGHT_TRIGGER] = 1.0 state = GamepadState(buttons={"gp_a": True}, axes=axes) assert state.digital_buttons() == {"gp_a", "gp_right_trigger"} # --- GamepadBindings --------------------------------------------------------------------------- def test_default_bindings_resolve_expected_actions(): bindings = GamepadBindings(dict(DEFAULT_GAMEPAD_BINDINGS)) assert bindings.action_for_button("gp_a") == "leap" assert bindings.action_for_button("gp_left_trigger") == "activate_left_hand_2" def test_unbound_button_resolves_to_none(): bindings = GamepadBindings({"leap": ["gp_a"]}) assert bindings.action_for_button("gp_y") is None def test_buttons_for_action_returns_the_configured_list(): bindings = GamepadBindings({"leap": ["gp_a", "gp_start"]}) assert bindings.buttons_for_action("leap") == ["gp_a", "gp_start"] def test_load_falls_back_to_defaults_when_file_missing(tmp_path): bindings = GamepadBindings.load(tmp_path / "does_not_exist.conf") assert bindings.action_for_button("gp_a") == "leap" def test_load_reads_conf_file_and_overrides_defaults(tmp_path): conf = tmp_path / "controller_bindings.conf" conf.write_text("[actions]\nleap = gp_y\n") bindings = GamepadBindings.load(conf) assert bindings.action_for_button("gp_y") == "leap" assert bindings.action_for_button("gp_a") is None # overridden, not appended # untouched actions still fall back to the defaults assert bindings.action_for_button("gp_left_bumper") == "block" def test_load_reads_the_real_shipped_controller_bindings_conf(): from pathlib import Path path = Path(__file__).resolve().parent.parent / "config" / "controller_bindings.conf" bindings = GamepadBindings.load(path) assert bindings.action_for_button("gp_a") == "leap" assert bindings.action_for_button("gp_dpad_up") == "select_ability_1"