"""Tests for elgato_cli.api.""" import json from unittest.mock import patch, MagicMock import requests from elgato_cli.api import ElgatoLight, LightState, mired_to_kelvin, kelvin_to_mired LIGHT_RESPONSE = { "numberOfLights": 1, "lights": [{"on": 1, "brightness": 50, "temperature": 200}], } def _make_mock_conn(response_data, status=200): """Create a mock HTTPConnection that returns the given response.""" mock_conn = MagicMock() mock_resp = MagicMock() mock_resp.status = status mock_resp.reason = "OK" if status == 200 else "Error" mock_resp.read.return_value = json.dumps(response_data).encode() mock_conn.getresponse.return_value = mock_resp return mock_conn class TestMiredKelvin: def test_mired_to_kelvin(self): assert mired_to_kelvin(143) == 6993 assert mired_to_kelvin(344) == 2907 assert mired_to_kelvin(200) == 5000 def test_kelvin_to_mired(self): assert kelvin_to_mired(5000) == 200 assert kelvin_to_mired(7000) == 143 assert kelvin_to_mired(2900) == 345 def test_roundtrip(self): for mired in [143, 200, 250, 300, 344]: assert abs(kelvin_to_mired(mired_to_kelvin(mired)) - mired) <= 1 class TestElgatoLight: @patch("elgato_cli.api.http.client.HTTPConnection") def test_get_state(self, mock_http_cls): mock_http_cls.return_value = _make_mock_conn(LIGHT_RESPONSE) light = ElgatoLight("192.168.1.100") state = light.get_state() assert state == LightState(on=True, brightness=50, temperature=200) mock_http_cls.assert_called_with("192.168.1.100", 9123, timeout=5) @patch("elgato_cli.api.http.client.HTTPConnection") def test_set_state_partial(self, mock_http_cls): updated = { "numberOfLights": 1, "lights": [{"on": 1, "brightness": 80, "temperature": 200}], } # First call: get_state (GET), second call: put (PUT) mock_http_cls.side_effect = [ _make_mock_conn(LIGHT_RESPONSE), _make_mock_conn(updated), ] light = ElgatoLight("192.168.1.100") state = light.set_state(brightness=80) assert state.brightness == 80 assert mock_http_cls.call_count == 2 @patch("elgato_cli.api.http.client.HTTPConnection") def test_toggle(self, mock_http_cls): toggled = { "numberOfLights": 1, "lights": [{"on": 0, "brightness": 50, "temperature": 200}], } # toggle calls: get_state, then set_state(get_state + put) mock_http_cls.side_effect = [ _make_mock_conn(LIGHT_RESPONSE), # toggle -> get_state _make_mock_conn(LIGHT_RESPONSE), # set_state -> get_state _make_mock_conn(toggled), # set_state -> put ] light = ElgatoLight("192.168.1.100") state = light.toggle() assert state.on is False @patch("elgato_cli.api.http.client.HTTPConnection") def test_get_info(self, mock_http_cls): info_resp = { "productName": "Elgato Key Light", "serialNumber": "AB12CD34", "firmwareVersion": "1.0.3", } mock_http_cls.return_value = _make_mock_conn(info_resp) light = ElgatoLight("192.168.1.100") info = light.get_info() assert info["productName"] == "Elgato Key Light" @patch("elgato_cli.api.time.sleep") @patch("elgato_cli.api.http.client.HTTPConnection") def test_retry_on_connection_error(self, mock_http_cls, mock_sleep): fail_conn = MagicMock() fail_conn.request.side_effect = ConnectionError("reset") ok_conn = _make_mock_conn(LIGHT_RESPONSE) mock_http_cls.side_effect = [fail_conn, ok_conn] light = ElgatoLight("192.168.1.100") state = light.get_state() assert state == LightState(on=True, brightness=50, temperature=200) assert mock_http_cls.call_count == 2 mock_sleep.assert_called_once_with(1.0) def test_custom_port(self): light = ElgatoLight("10.0.0.5", port=8080) assert light.base_url == "http://10.0.0.5:8080/elgato"