defmodule Microwaveprop.Weather.SoundingTest do use Microwaveprop.DataCase, async: true alias Microwaveprop.Weather.Sounding alias Microwaveprop.Weather.Station defp create_sounding_station do %Station{} |> Station.changeset(%{ station_code: "FWD", station_type: "sounding", wmo_number: 72_249, name: "Fort Worth", lat: 32.83, lon: -97.30 }) |> Repo.insert!() end @sample_profile [ %{"pres" => 1013.0, "hght" => 171, "tmpc" => 25.0, "dwpc" => 15.0, "drct" => 180, "sknt" => 10}, %{"pres" => 925.0, "hght" => 800, "tmpc" => 20.0, "dwpc" => 12.0, "drct" => 200, "sknt" => 15}, %{"pres" => 850.0, "hght" => 1500, "tmpc" => 15.0, "dwpc" => 8.0, "drct" => 220, "sknt" => 20} ] @valid_sounding_attrs %{ observed_at: ~U[2026-03-28 12:00:00Z], profile: @sample_profile, level_count: 3, surface_pressure_mb: 1013.0, surface_temp_c: 25.0, surface_dewpoint_c: 15.0, surface_refractivity: 320.5, min_refractivity_gradient: -45.0, boundary_layer_depth_m: 1200.0, precipitable_water_mm: 25.0, k_index: 28.0, lifted_index: -2.0, ducting_detected: false, duct_characteristics: nil } describe "changeset/2" do test "valid attributes with station_id" do station = create_sounding_station() attrs = Map.put(@valid_sounding_attrs, :station_id, station.id) changeset = Sounding.changeset(%Sounding{}, attrs) assert changeset.valid? end test "requires station_id, observed_at, profile, level_count" do changeset = Sounding.changeset(%Sounding{}, %{}) assert %{ station_id: ["can't be blank"], observed_at: ["can't be blank"], profile: ["can't be blank"], level_count: ["can't be blank"] } = errors_on(changeset) end test "derived params are optional" do station = create_sounding_station() attrs = %{ station_id: station.id, observed_at: ~U[2026-03-28 12:00:00Z], profile: @sample_profile, level_count: 3 } changeset = Sounding.changeset(%Sounding{}, attrs) assert changeset.valid? end test "persists to the database with JSONB profile" do station = create_sounding_station() attrs = Map.put(@valid_sounding_attrs, :station_id, station.id) changeset = Sounding.changeset(%Sounding{}, attrs) assert {:ok, sounding} = Repo.insert(changeset) assert length(sounding.profile) == 3 assert hd(sounding.profile)["pres"] == 1013.0 assert sounding.ducting_detected == false assert sounding.k_index == 28.0 end test "persists duct_characteristics as JSONB" do station = create_sounding_station() duct_chars = [ %{"base" => 200, "top" => 500, "strength" => "5.2"} ] attrs = @valid_sounding_attrs |> Map.put(:station_id, station.id) |> Map.put(:ducting_detected, true) |> Map.put(:duct_characteristics, duct_chars) changeset = Sounding.changeset(%Sounding{}, attrs) assert {:ok, sounding} = Repo.insert(changeset) assert sounding.ducting_detected == true assert [%{"base" => 200, "top" => 500}] = sounding.duct_characteristics end test "enforces unique station_id + observed_at" do station = create_sounding_station() attrs = Map.put(@valid_sounding_attrs, :station_id, station.id) assert {:ok, _} = %Sounding{} |> Sounding.changeset(attrs) |> Repo.insert() assert {:error, changeset} = %Sounding{} |> Sounding.changeset(attrs) |> Repo.insert() assert %{station_id: ["has already been taken"]} = errors_on(changeset) end end end