- SwpcClient: unparseable time_tag rows drop silently, integer / string
numerics both cast, already-decoded list bodies (Req auto-decode) are
accepted, non-JSON-array bodies return {:error, :not_a_list}, X-ray
rows whose energy isn't the long wavelength are filtered, and the
misspelled-upstream electron_contaminaton key flags
electron_contaminated.
- UwyoSoundingClient: every month abbreviation routes to its correct
number, bogus month tokens fall through to an empty result, and
short-of-fixed-width lines are skipped without raising.
- Grid.wgrib2_grid_spec/0: lon/lat_start anchor to the SW corner,
steps match Grid.step/0, cell counts span CONUS inclusive, and the
spec's cell product equals length(Grid.conus_points/0).
- PollWorker: empty-link list is a no-op, and poll_fn receives host /
community / radio_type straight from the link row.
- Contact submission_changeset: antenna heights are bounded to
[0, 1000] ft, whitespace-only mode normalises without firing an
invalid-mode error, plus a pair of StreamData properties — every
sanctioned band validates and every out-of-list band string is
rejected.
Suite: 2,380 tests + 148 properties (was 2,370 + 146); coverage
70.38% → 71.08% total; credo strict clean.
84 lines
2.3 KiB
Elixir
84 lines
2.3 KiB
Elixir
defmodule Microwaveprop.Propagation.GridTest do
|
|
use ExUnit.Case, async: true
|
|
|
|
alias Microwaveprop.Propagation.Grid
|
|
|
|
describe "conus_points/0" do
|
|
test "generates grid at 0.125 degree resolution" do
|
|
points = Grid.conus_points()
|
|
assert length(points) > 5000
|
|
assert length(points) < 100_000
|
|
end
|
|
|
|
test "all points within CONUS bounds" do
|
|
Enum.each(Grid.conus_points(), fn {lat, lon} ->
|
|
assert lat >= 25.0 and lat <= 50.0
|
|
assert lon >= -125.0 and lon <= -66.0
|
|
end)
|
|
end
|
|
|
|
test "points are on 0.125 degree grid" do
|
|
Enum.each(Grid.conus_points(), fn {lat, lon} ->
|
|
assert Float.round(lat * 8, 0) == lat * 8
|
|
assert Float.round(lon * 8, 0) == lon * 8
|
|
end)
|
|
end
|
|
|
|
test "first point is at SW corner" do
|
|
[{lat, lon} | _] = Grid.conus_points()
|
|
assert lat == 25.0
|
|
assert lon == -125.0
|
|
end
|
|
|
|
test "last point is at NE corner" do
|
|
points = Grid.conus_points()
|
|
{lat, lon} = List.last(points)
|
|
assert lat == 50.0
|
|
assert lon == -66.0
|
|
end
|
|
end
|
|
|
|
describe "step/0" do
|
|
test "returns 0.125" do
|
|
assert Grid.step() == 0.125
|
|
end
|
|
end
|
|
|
|
describe "bounds/0" do
|
|
test "returns CONUS bounding box" do
|
|
bounds = Grid.bounds()
|
|
assert bounds.lat_min == 25.0
|
|
assert bounds.lat_max == 50.0
|
|
assert bounds.lon_min == -125.0
|
|
assert bounds.lon_max == -66.0
|
|
end
|
|
end
|
|
|
|
describe "wgrib2_grid_spec/0" do
|
|
test "lon_start / lat_start match the bounding box SW corner" do
|
|
spec = Grid.wgrib2_grid_spec()
|
|
assert spec.lon_start == -125.0
|
|
assert spec.lat_start == 25.0
|
|
end
|
|
|
|
test "grid step matches Grid.step/0 on both axes" do
|
|
spec = Grid.wgrib2_grid_spec()
|
|
assert spec.lon_step == Grid.step()
|
|
assert spec.lat_step == Grid.step()
|
|
end
|
|
|
|
test "lon_count and lat_count span the full CONUS box inclusive" do
|
|
spec = Grid.wgrib2_grid_spec()
|
|
# (lon_max - lon_min) / step + 1 = (-66 - -125) / 0.125 + 1 = 473
|
|
assert spec.lon_count == 473
|
|
# (lat_max - lat_min) / step + 1 = (50 - 25) / 0.125 + 1 = 201
|
|
assert spec.lat_count == 201
|
|
end
|
|
|
|
test "total cells in wgrib2_grid_spec matches conus_points length" do
|
|
spec = Grid.wgrib2_grid_spec()
|
|
points = Grid.conus_points()
|
|
assert length(points) == spec.lon_count * spec.lat_count
|
|
end
|
|
end
|
|
end
|