- Add jump_credo_checks ~> 0.4 with all 20 checks enabled - Fix all standard Credo issues: 139 @spec (113 done, 26 remain), 4 refactoring, 3 alias usage, 9 System.cmd env, 5 unsafe_to_atom, 2 max line length, 9 assert_receive timeout - Fix 170+ jump_credo_checks warnings: - 117 TopLevelAliasImportRequire: move nested alias/import to module top - 32 UseObanProWorker: switch to Oban.Pro.Worker - 4 DoctestIExExamples: add doctests / create test file - ~20 WeakAssertion: strengthen type-check assertions - Various ConditionalAssertion, AssertReceiveTimeout fixes - Exclude vendor/ from Credo analysis - Remaining: 175 warnings (mostly opinionated WeakAssertion, AvoidSocketAssignsInTest), 26 @spec annotations
149 lines
5.1 KiB
Elixir
149 lines
5.1 KiB
Elixir
defmodule Microwaveprop.RadioRefinementTest do
|
|
use Microwaveprop.DataCase, async: true
|
|
|
|
alias Microwaveprop.Radio
|
|
alias Microwaveprop.Radio.Contact
|
|
alias Microwaveprop.Terrain.ElevationClient
|
|
alias Microwaveprop.Weather.HrrrClient
|
|
alias Microwaveprop.Weather.IemClient
|
|
|
|
setup do
|
|
Req.Test.stub(IemClient, fn conn ->
|
|
case conn.request_path do
|
|
"/cgi-bin/request/asos.py" -> Req.Test.text(conn, "#DEBUG,\nstation,valid,tmpf\n")
|
|
_ -> Req.Test.json(conn, %{"profiles" => []})
|
|
end
|
|
end)
|
|
|
|
Req.Test.stub(HrrrClient, fn conn ->
|
|
Plug.Conn.send_resp(conn, 404, "not found")
|
|
end)
|
|
|
|
Req.Test.stub(ElevationClient, fn conn ->
|
|
params = Plug.Conn.fetch_query_params(conn).query_params
|
|
lat_count = params["latitude"] |> String.split(",") |> length()
|
|
Req.Test.json(conn, %{"elevation" => List.duplicate(200.0, lat_count)})
|
|
end)
|
|
|
|
:ok
|
|
end
|
|
|
|
defp insert_contact(attrs \\ %{}) do
|
|
base = %{
|
|
station1: "W5XD",
|
|
station2: "K5TR",
|
|
grid1: "EM12",
|
|
grid2: "EM00",
|
|
band: "10000",
|
|
mode: "CW",
|
|
qso_timestamp: ~U[2026-03-28 18:00:00Z],
|
|
submitter_email: "test@example.com"
|
|
}
|
|
|
|
{:ok, contact} = Radio.create_contact(Map.merge(base, attrs))
|
|
contact
|
|
end
|
|
|
|
defp mark_all_enrichment_complete(%Contact{} = contact) do
|
|
contact
|
|
|> Ecto.Changeset.change(%{
|
|
hrrr_status: :complete,
|
|
weather_status: :complete,
|
|
terrain_status: :complete,
|
|
iemre_status: :complete
|
|
})
|
|
|> Repo.update!()
|
|
end
|
|
|
|
describe "apply_contact_refinement/2" do
|
|
test "refining grid1 updates grid1, pos1, distance, and resets all enrichment statuses" do
|
|
contact = mark_all_enrichment_complete(insert_contact())
|
|
original_grid2 = contact.grid2
|
|
original_pos2 = contact.pos2
|
|
|
|
assert {:ok, refined} = Radio.apply_contact_refinement(contact, %{grid1: "EM12KP"})
|
|
|
|
assert refined.grid1 == "EM12KP"
|
|
assert refined.grid2 == original_grid2
|
|
assert refined.pos2 == original_pos2
|
|
refute refined.pos1 == contact.pos1
|
|
assert refined.distance_km
|
|
assert refined.hrrr_status == :pending
|
|
assert refined.weather_status == :pending
|
|
assert refined.terrain_status == :pending
|
|
assert refined.iemre_status == :pending
|
|
end
|
|
|
|
test "refining grid2 updates grid2, pos2, distance, and resets all enrichment statuses" do
|
|
contact = mark_all_enrichment_complete(insert_contact())
|
|
original_grid1 = contact.grid1
|
|
original_pos1 = contact.pos1
|
|
|
|
assert {:ok, refined} = Radio.apply_contact_refinement(contact, %{grid2: "EM00CD"})
|
|
|
|
assert refined.grid1 == original_grid1
|
|
assert refined.pos1 == original_pos1
|
|
assert refined.grid2 == "EM00CD"
|
|
refute refined.pos2 == contact.pos2
|
|
assert refined.hrrr_status == :pending
|
|
assert refined.weather_status == :pending
|
|
assert refined.terrain_status == :pending
|
|
assert refined.iemre_status == :pending
|
|
end
|
|
|
|
test "refining both grids updates both + recomputes distance" do
|
|
contact = mark_all_enrichment_complete(insert_contact())
|
|
|
|
assert {:ok, refined} =
|
|
Radio.apply_contact_refinement(contact, %{grid1: "EM12KP", grid2: "EM00CD"})
|
|
|
|
assert refined.grid1 == "EM12KP"
|
|
assert refined.grid2 == "EM00CD"
|
|
assert refined.distance_km
|
|
# Distances remain similar (grids refined within same squares) but pos values change.
|
|
refute refined.pos1 == contact.pos1
|
|
refute refined.pos2 == contact.pos2
|
|
end
|
|
|
|
test "refining only :mode updates mode without touching pos/distance or statuses" do
|
|
contact = %{mode: nil} |> insert_contact() |> mark_all_enrichment_complete()
|
|
original_pos1 = contact.pos1
|
|
original_pos2 = contact.pos2
|
|
original_distance = contact.distance_km
|
|
|
|
assert {:ok, refined} = Radio.apply_contact_refinement(contact, %{mode: "CW"})
|
|
|
|
assert refined.mode == "CW"
|
|
assert refined.pos1 == original_pos1
|
|
assert refined.pos2 == original_pos2
|
|
assert refined.distance_km == original_distance
|
|
assert refined.hrrr_status == :complete
|
|
assert refined.weather_status == :complete
|
|
assert refined.terrain_status == :complete
|
|
assert refined.iemre_status == :complete
|
|
end
|
|
|
|
test "empty changes map returns the contact unchanged" do
|
|
contact = mark_all_enrichment_complete(insert_contact())
|
|
assert {:ok, unchanged} = Radio.apply_contact_refinement(contact, %{})
|
|
assert unchanged.id == contact.id
|
|
assert unchanged.grid1 == contact.grid1
|
|
assert unchanged.grid2 == contact.grid2
|
|
assert unchanged.mode == contact.mode
|
|
assert unchanged.hrrr_status == :complete
|
|
end
|
|
|
|
test "invalid Maidenhead grid returns error and does not mutate the DB row" do
|
|
contact = mark_all_enrichment_complete(insert_contact())
|
|
|
|
assert {:error, %Ecto.Changeset{} = changeset} =
|
|
Radio.apply_contact_refinement(contact, %{grid1: "ZZZZ"})
|
|
|
|
refute changeset.valid?
|
|
|
|
reloaded = Repo.reload!(contact)
|
|
assert reloaded.grid1 == contact.grid1
|
|
assert reloaded.hrrr_status == :complete
|
|
end
|
|
end
|
|
end
|