test_util.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. """Tests for config-field normalisation.
  2. Station and device IDs are copy-pasted out of the browser's Network tab, so they
  3. routinely arrive with a stray leading or trailing space. The upstream API
  4. treats " 4235…" as a different, invalid value and the user only sees a generic
  5. "cannot connect".
  6. """
  7. from __future__ import annotations
  8. import pytest
  9. from custom_components.solar_of_things.const import WHITESPACE_SENSITIVE_FIELDS
  10. from custom_components.solar_of_things.util import normalise_config_fields
  11. def test_trims_pasted_station_and_device_ids() -> None:
  12. cleaned = normalise_config_fields(
  13. {"station_id": "486217907720650752 ", "device_id": " 486217907745816576"}
  14. )
  15. assert cleaned["station_id"] == "486217907720650752"
  16. assert cleaned["device_id"] == "486217907745816576"
  17. def test_password_is_never_trimmed() -> None:
  18. """Whitespace in a password may be intentional, so it must survive."""
  19. cleaned = normalise_config_fields({"password": " hunter2 ", "user_id": " bob "})
  20. assert cleaned["password"] == " hunter2 "
  21. assert cleaned["user_id"] == "bob"
  22. def test_password_is_excluded_from_the_field_list() -> None:
  23. assert "password" not in WHITESPACE_SENSITIVE_FIELDS
  24. def test_trims_a_pasted_iot_token() -> None:
  25. """Tokens are copied out of DevTools and often carry a newline or tab."""
  26. cleaned = normalise_config_fields({"iot_token": "\n eyJhbGciOi.token.value \t"})
  27. assert cleaned["iot_token"] == "eyJhbGciOi.token.value"
  28. @pytest.mark.parametrize(
  29. ("key", "value"),
  30. [
  31. ("access_token_expires", "2026-01-01T00:00:00+00:00"),
  32. ("refresh_token", None),
  33. ("some_number", 5),
  34. ],
  35. )
  36. def test_unlisted_and_non_string_values_pass_through(key, value) -> None:
  37. assert normalise_config_fields({key: value})[key] == value
  38. def test_returns_a_copy_without_mutating_the_input() -> None:
  39. """entry.data is a read-only mapping in HA; never write through it."""
  40. source = {"station_id": " 123 "}
  41. cleaned = normalise_config_fields(source)
  42. assert source["station_id"] == " 123 "
  43. assert cleaned["station_id"] == "123"
  44. assert cleaned is not source
  45. @pytest.mark.parametrize(
  46. ("payload", "expected"),
  47. [
  48. ({}, {}),
  49. ({"unrelated": "x"}, {"unrelated": "x"}),
  50. ({"station_id": " "}, {"station_id": ""}),
  51. ],
  52. )
  53. def test_edge_cases(payload, expected) -> None:
  54. assert normalise_config_fields(payload) == expected