defmodule Microwaveprop.Terrain.TerrainProfileTest do use Microwaveprop.DataCase, async: true alias Microwaveprop.Radio.Contact alias Microwaveprop.Terrain.TerrainProfile @qso_attrs %{ station1: "W5XD", station2: "K5TR", qso_timestamp: ~U[2026-03-28 18:00:00Z], mode: "CW", band: Decimal.new("1296"), pos1: %{"lat" => 32.9, "lon" => -97.0}, pos2: %{"lat" => 30.3, "lon" => -97.7} } defp create_contact do {:ok, contact} = %Contact{} |> Contact.changeset(@qso_attrs) |> Repo.insert() contact end describe "changeset/2" do test "valid with required fields" do contact = create_contact() attrs = %{ contact_id: contact.id, sample_count: 65, path_points: [%{"lat" => 32.9, "lon" => -97.0, "elev" => 200.0, "dist_km" => 0.0}], verdict: "CLEAR" } changeset = TerrainProfile.changeset(%TerrainProfile{}, attrs) assert changeset.valid? end test "invalid without required fields" do changeset = TerrainProfile.changeset(%TerrainProfile{}, %{}) refute changeset.valid? errors = errors_on(changeset) assert errors[:contact_id] assert errors[:sample_count] assert errors[:path_points] assert errors[:verdict] end test "valid with all optional fields" do contact = create_contact() attrs = %{ contact_id: contact.id, sample_count: 65, path_points: [%{"lat" => 32.9, "lon" => -97.0, "elev" => 200.0, "dist_km" => 0.0}], verdict: "BLOCKED", max_elevation_m: 450.0, min_clearance_m: -12.5, diffraction_db: 8.3, fresnel_hit_count: 3, obstructed_count: 1 } changeset = TerrainProfile.changeset(%TerrainProfile{}, attrs) assert changeset.valid? end test "enforces unique contact_id constraint on insert" do contact = create_contact() attrs = %{ contact_id: contact.id, sample_count: 65, path_points: [], verdict: "CLEAR" } {:ok, _} = %TerrainProfile{} |> TerrainProfile.changeset(attrs) |> Repo.insert() {:error, changeset} = %TerrainProfile{} |> TerrainProfile.changeset(attrs) |> Repo.insert() assert errors_on(changeset)[:contact_id] end end end