using Evergreen.Health.Application.Health.Integrations.HomeAssistant; using Microsoft.Extensions.Options; using System.Net; using System.Text; using Xunit; namespace Admin.NET.Test.Health; public sealed class HomeAssistantTemperatureUnitTests { [Theory] [InlineData("°C")] [InlineData("°F")] public async Task NativeClimateWithoutUnitUsesHaUnitSystemWithoutGuessing(string unit) { var handler = new UnitHandler("""[{"entity_id":"climate.room","state":"off","attributes":{"temperature":23,"min_temp":5,"max_temp":35,"target_temp_step":0.5,"supported_features":393}}]""", unit); var states = await Client(handler).GetStatesAsync(); var state = Assert.Single(states); Assert.Equal(unit, state.GetStringAttribute("temperature_unit")); Assert.Equal(23d, state.GetDoubleAttribute("temperature")); Assert.Equal(393d, state.GetDoubleAttribute("supported_features")); Assert.Equal(new[] { "/api/states", "/api/config" }, handler.Paths); } [Fact] public async Task ExplicitDeviceUnitIsNotOverwritten() { var handler = new UnitHandler("""[{"entity_id":"climate.room","state":"off","attributes":{"temperature_unit":"°F","temperature":73}}]""", "°C"); var state = Assert.Single(await Client(handler).GetStatesAsync()); Assert.Equal("°F", state.GetStringAttribute("temperature_unit")); Assert.Equal(new[] { "/api/states" }, handler.Paths); } [Fact] public async Task MissingConfigKeepsUnitUnknownAndDoesNotHideOtherDevices() { var handler = new UnitHandler("""[{"entity_id":"climate.room","state":"off","attributes":{"temperature":23}},{"entity_id":"switch.room","state":"on","attributes":{}}]""", "°C", HttpStatusCode.ServiceUnavailable); var states = await Client(handler).GetStatesAsync(); Assert.Equal(2, states.Count); Assert.Null(states[0].GetStringAttribute("temperature_unit")); Assert.Equal("on", states[1].State); Assert.Equal(23d, states[0].GetDoubleAttribute("temperature")); } [Fact] public async Task OtherDevicesDoNotRequireUnitProbe() { var handler = new UnitHandler("""[{"entity_id":"cover.room","state":"unavailable","attributes":{"supported_features":15}}]""", "°C"); Assert.Single(await Client(handler).GetStatesAsync()); Assert.Equal(new[] { "/api/states" }, handler.Paths); } private static HomeAssistantClient Client(UnitHandler handler) => new(new HttpClient(handler), Options.Create(new HomeAssistantOptions { BaseUrl = "https://ha.example.invalid", AccessToken = "fake-test-token" })); private sealed class UnitHandler(string states, string unit, HttpStatusCode configStatus = HttpStatusCode.OK) : HttpMessageHandler { public List Paths { get; } = []; protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Assert.Equal(HttpMethod.Get, request.Method); var path = request.RequestUri!.AbsolutePath; Paths.Add(path); var content = path == "/api/states" ? states : System.Text.Json.JsonSerializer.Serialize(new { unit_system = new { temperature = unit } }); return Task.FromResult(new HttpResponseMessage(path == "/api/states" ? HttpStatusCode.OK : configStatus) { Content = new StringContent(content, Encoding.UTF8, "application/json") }); } } }