Repository: home-assistant/core
File: tests/components/tuya/test_binary_sensor.py (Python)

Code before:
    tankfull: str,
    defrost: str,
    wet: str,
) -> None:
    """Test BITMAP fault sensor on cs_zibqa9dutqyaxym2."""
    await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)

    assert hass.states.get("binary_sensor.dehumidifier_tank_full").state == "off"
    assert hass.states.get("binary_sensor.dehumidifier_defrost").state == "off"
    assert hass.states.get("binary_sensor.dehumidifier_wet").state == "off"

    await mock_listener.async_send_device_update(
        hass, mock_device, {"fault": fault_value}
    )

    assert hass.states.get("binary_sensor.dehumidifier_tank_full").state == tankfull
    assert hass.states.get("binary_sensor.dehumidifier_defrost").state == defrost
    assert hass.states.get("binary_sensor.dehumidifier_wet").state == wet


@pytest.mark.parametrize(
    "mock_device_code",
    ["mcs_oxslv1c9"],
)
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.BINARY_SENSOR])
async def test_update_only_when_dpcode_in_updated_properties(
    hass: HomeAssistant,
    mock_manager: Manager,
    mock_config_entry: MockConfigEntry,
    mock_device: CustomerDevice,
    mock_listener: MockDeviceListener,
) -> None:
    """Test binary sensor only updates when its dpcode is in updated properties.

    This test verifies that when an update event comes with properties that do NOT
    include the binary sensor's dpcode (e.g., a battery event for a door sensor),
    the binary sensor state is not changed.
    """
    await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)

    # Initial state should be off (doorcontact_state is false in fixture)
    state = hass.states.get("binary_sensor.window_downstairs_door")
    assert state is not None
    assert state.state == "off"
    initial_last_changed = state.last_changed

    # Manually change the device status to simulate a stale value
    # that should NOT be reflected since battery_percentage is not doorcontact_state
    mock_device.status["doorcontact_state"] = True

    # Send an update with only battery_percentage - door sensor should NOT update

Review comment (suggestion):
It would be better to use `pytest.mark.parametrize` with just one single test.
See example in #160407

Code after:
    mock_listener: MockDeviceListener,
    fault_value: int,
    tankfull: str,
    defrost: str,
    wet: str,
) -> None:
    """Test BITMAP fault sensor on cs_zibqa9dutqyaxym2."""
    await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)

    assert hass.states.get("binary_sensor.dehumidifier_tank_full").state == "off"
    assert hass.states.get("binary_sensor.dehumidifier_defrost").state == "off"
    assert hass.states.get("binary_sensor.dehumidifier_wet").state == "off"

    await mock_listener.async_send_device_update(
        hass, mock_device, {"fault": fault_value}
    )

    assert hass.states.get("binary_sensor.dehumidifier_tank_full").state == tankfull
    assert hass.states.get("binary_sensor.dehumidifier_defrost").state == defrost
    assert hass.states.get("binary_sensor.dehumidifier_wet").state == wet


@pytest.mark.parametrize(
    "mock_device_code",
    ["mcs_oxslv1c9"],
)
@pytest.mark.parametrize(
    ("updates", "expected_state", "last_reported"),
    [
        # Update without dpcode - state should not change, last_reported stays at initial
        ({"battery_percentage": 80}, "off", "2024-01-01T00:00:00+00:00"),
        # Update with dpcode - state should change, last_reported advances
        ({"doorcontact_state": True}, "on", "2024-01-01T00:01:00+00:00"),
        # Update with multiple properties including dpcode - state should change
        (
            {"battery_percentage": 50, "doorcontact_state": True},
            "on",
            "2024-01-01T00:01:00+00:00",
        ),
    ],
)
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.BINARY_SENSOR])
@pytest.mark.freeze_time("2024-01-01")
async def test_selective_state_update(
    hass: HomeAssistant,
    mock_manager: Manager,
    mock_config_entry: MockConfigEntry,
    mock_device: CustomerDevice,
    mock_listener: MockDeviceListener,
    freezer: FrozenDateTimeFactory,
    updates: dict[str, Any],