defmodule Microwaveprop.Backtest.FeaturesTest do use Microwaveprop.DataCase, async: true alias Microwaveprop.Backtest.Features alias Microwaveprop.Weather @point_lat 32.9 @point_lon -97.0 @valid_time ~U[2026-03-28 18:00:00Z] defp create_profile(attrs) do base = %{ valid_time: @valid_time, lat: @point_lat, lon: @point_lon } {:ok, _} = Weather.upsert_hrrr_profile(Map.merge(base, attrs)) end describe "naive_gradient/3" do test "returns the nearest profile's min_refractivity_gradient" do create_profile(%{min_refractivity_gradient: -250.0}) assert Features.naive_gradient(@point_lat, @point_lon, @valid_time) == -250.0 end test "returns nil when no profile is within match window" do assert Features.naive_gradient(@point_lat, @point_lon, @valid_time) == nil end end describe "td_depression/3" do test "returns surface_temp_c minus surface_dewpoint_c" do create_profile(%{surface_temp_c: 20.0, surface_dewpoint_c: 14.0}) assert Features.td_depression(@point_lat, @point_lon, @valid_time) == 6.0 end test "returns nil when profile has no surface data" do create_profile(%{surface_temp_c: nil, surface_dewpoint_c: nil}) assert Features.td_depression(@point_lat, @point_lon, @valid_time) == nil end end describe "time_of_day/3" do test "returns UTC hour + minute fraction and never calls the database" do assert Features.time_of_day(0.0, 0.0, ~U[2026-01-01 06:30:00Z]) == 6.5 assert Features.time_of_day(0.0, 0.0, ~U[2026-01-01 00:00:00Z]) == 0.0 assert Features.time_of_day(0.0, 0.0, ~U[2026-01-01 23:45:00Z]) == 23.75 end end describe "pressure/3" do test "returns surface_pressure_mb from the nearest profile" do create_profile(%{surface_pressure_mb: 1013.2}) assert Features.pressure(@point_lat, @point_lon, @valid_time) == 1013.2 end test "returns nil when no profile exists" do assert Features.pressure(@point_lat, @point_lon, @valid_time) == nil end end end