159 lines
4.8 KiB
Elixir
159 lines
4.8 KiB
Elixir
defmodule Microwaveprop.Terrain.ElevationClientTest do
|
|
use ExUnit.Case, async: true
|
|
|
|
alias Microwaveprop.Terrain.ElevationClient
|
|
|
|
describe "sample_path/5" do
|
|
test "generates N+1 evenly spaced points" do
|
|
points = ElevationClient.sample_path(32.9, -97.0, 30.3, -97.7, 4)
|
|
|
|
assert length(points) == 5
|
|
|
|
first = hd(points)
|
|
last = List.last(points)
|
|
|
|
assert_in_delta first.lat, 32.9, 0.001
|
|
assert_in_delta first.lon, -97.0, 0.001
|
|
assert_in_delta first.d, 0.0, 0.001
|
|
|
|
assert_in_delta last.lat, 30.3, 0.001
|
|
assert_in_delta last.lon, -97.7, 0.001
|
|
assert_in_delta last.d, 1.0, 0.001
|
|
end
|
|
|
|
test "midpoint is correct" do
|
|
points = ElevationClient.sample_path(0.0, 0.0, 10.0, 10.0, 2)
|
|
|
|
mid = Enum.at(points, 1)
|
|
assert_in_delta mid.lat, 5.0, 0.001
|
|
assert_in_delta mid.lon, 5.0, 0.001
|
|
assert_in_delta mid.d, 0.5, 0.001
|
|
end
|
|
end
|
|
|
|
describe "fetch_elevation_profile/5" do
|
|
test "returns profile with elevations from Open-Meteo" do
|
|
Req.Test.stub(ElevationClient, fn conn ->
|
|
Req.Test.json(conn, %{"elevation" => [200.0, 250.0, 180.0]})
|
|
end)
|
|
|
|
assert {:ok, profile} =
|
|
ElevationClient.fetch_elevation_profile(32.9, -97.0, 30.3, -97.7, 2)
|
|
|
|
assert length(profile) == 3
|
|
|
|
first = hd(profile)
|
|
assert Map.has_key?(first, :lat)
|
|
assert Map.has_key?(first, :lon)
|
|
assert Map.has_key?(first, :elev)
|
|
assert Map.has_key?(first, :dist_km)
|
|
assert first.elev == 200.0
|
|
assert_in_delta first.dist_km, 0.0, 0.001
|
|
end
|
|
|
|
test "batches requests when more than 100 points" do
|
|
call_count = :counters.new(1, [:atomics])
|
|
|
|
Req.Test.stub(ElevationClient, fn conn ->
|
|
:counters.add(call_count, 1, 1)
|
|
# Return 101 elevations for first batch, or however many requested
|
|
params = Plug.Conn.fetch_query_params(conn).query_params
|
|
lat_count = params["latitude"] |> String.split(",") |> length()
|
|
elevations = List.duplicate(100.0, lat_count)
|
|
Req.Test.json(conn, %{"elevation" => elevations})
|
|
end)
|
|
|
|
assert {:ok, profile} =
|
|
ElevationClient.fetch_elevation_profile(32.9, -97.0, 30.3, -97.7, 150)
|
|
|
|
# 151 points → 2 batches (100 + 51)
|
|
assert length(profile) == 151
|
|
assert :counters.get(call_count, 1) == 2
|
|
end
|
|
|
|
test "falls back to Open-Topo-Data on Open-Meteo failure" do
|
|
call_count = :counters.new(1, [:atomics])
|
|
|
|
Req.Test.stub(ElevationClient, fn conn ->
|
|
:counters.add(call_count, 1, 1)
|
|
current = :counters.get(call_count, 1)
|
|
|
|
if current == 1 do
|
|
# First call (Open-Meteo) fails
|
|
Plug.Conn.send_resp(conn, 500, "error")
|
|
else
|
|
# Second call (Open-Topo-Data) succeeds
|
|
Req.Test.json(conn, %{
|
|
"status" => "OK",
|
|
"results" => [
|
|
%{"elevation" => 100.0},
|
|
%{"elevation" => 150.0},
|
|
%{"elevation" => 120.0}
|
|
]
|
|
})
|
|
end
|
|
end)
|
|
|
|
assert {:ok, profile} =
|
|
ElevationClient.fetch_elevation_profile(32.9, -97.0, 30.3, -97.7, 2)
|
|
|
|
assert length(profile) == 3
|
|
assert hd(profile).elev == 100.0
|
|
end
|
|
|
|
test "returns error when both APIs fail" do
|
|
Req.Test.stub(ElevationClient, fn conn ->
|
|
Plug.Conn.send_resp(conn, 500, "error")
|
|
end)
|
|
|
|
assert {:error, _reason} =
|
|
ElevationClient.fetch_elevation_profile(32.9, -97.0, 30.3, -97.7, 2)
|
|
end
|
|
end
|
|
end
|
|
|
|
defmodule Microwaveprop.Terrain.ElevationClientSrtmTest do
|
|
use ExUnit.Case, async: false
|
|
|
|
alias Microwaveprop.Terrain.ElevationClient
|
|
|
|
@tiles_dir Path.expand("~/srtm/tiles")
|
|
@has_tiles File.exists?(Path.join(@tiles_dir, "N32W097.hgt"))
|
|
|
|
setup do
|
|
prev = Application.get_env(:microwaveprop, :srtm_tiles_dir)
|
|
|
|
on_exit(fn ->
|
|
if prev,
|
|
do: Application.put_env(:microwaveprop, :srtm_tiles_dir, prev),
|
|
else: Application.delete_env(:microwaveprop, :srtm_tiles_dir)
|
|
end)
|
|
|
|
:ok
|
|
end
|
|
|
|
describe "SRTM integration" do
|
|
@tag :srtm
|
|
@tag skip: !@has_tiles && "SRTM tiles not available"
|
|
test "uses local SRTM tiles when configured" do
|
|
Application.put_env(:microwaveprop, :srtm_tiles_dir, @tiles_dir)
|
|
|
|
assert {:ok, profile} =
|
|
ElevationClient.fetch_elevation_profile(32.78, -96.8, 32.5, -96.5, 4)
|
|
|
|
assert length(profile) == 5
|
|
assert hd(profile).elev > 0
|
|
end
|
|
|
|
@tag :srtm
|
|
test "returns zero elevation when SRTM tiles missing (no API fallback)" do
|
|
Application.put_env(:microwaveprop, :srtm_tiles_dir, "/nonexistent/tiles")
|
|
|
|
assert {:ok, profile} =
|
|
ElevationClient.fetch_elevation_profile(32.9, -97.0, 30.3, -97.7, 2)
|
|
|
|
assert length(profile) == 3
|
|
assert Enum.all?(profile, fn p -> p.elev == 0 end)
|
|
end
|
|
end
|
|
end
|