towerops/test/towerops/geocoding_test.exs
Graham McIntire 3ca0834ef0 tests: raise coverage to 70% via helper promotion + new unit/property tests
Promoted pure presentation and utility helpers from `defp` to `def @doc false`
across ~20 LiveViews, Oban workers, and sync modules so they're reachable from
unit tests. Refactored several `cond` blocks into idiomatic function heads with
guards. Added ~250 new test cases in new files under test/towerops and
test/towerops_web, including DB-backed tests for CnMaestro.Sync and
AlertNotificationWorker, and removed dead LiveView tab components and
CapacityLive (no callers anywhere in lib/test).

Configured mix.exs test_coverage.ignore_modules to exclude vendored third-party
code (SnmpKit, protobuf-generated Towerops.Agent.*, Absinthe GraphQL types,
Phoenix HTML modules, Inspect protocol impls) from coverage calculations —
these are not our project code.

Coverage: 66.93% → 70.09%. Full suite: 10,127 tests, 0 failures.
2026-04-24 09:49:06 -05:00

140 lines
4.1 KiB
Elixir

defmodule Towerops.GeocodingTest do
use ExUnit.Case, async: false
alias Towerops.Geocoding
setup do
original = Application.get_env(:towerops, :google_maps_api_key)
Application.put_env(:towerops, :google_maps_api_key, "test-key")
on_exit(fn ->
if is_nil(original) do
Application.delete_env(:towerops, :google_maps_api_key)
else
Application.put_env(:towerops, :google_maps_api_key, original)
end
end)
:ok
end
describe "geocode/1" do
test "returns lat/lng/formatted_address on OK response" do
Req.Test.stub(Geocoding, fn conn ->
assert conn.query_string =~ "address="
assert conn.query_string =~ "key=test-key"
Req.Test.json(conn, %{
"status" => "OK",
"results" => [
%{
"geometry" => %{"location" => %{"lat" => 40.7128, "lng" => -74.006}},
"formatted_address" => "New York, NY, USA"
}
]
})
end)
assert {:ok, result} = Geocoding.geocode("New York")
assert result.latitude == 40.7128
assert result.longitude == -74.006
assert result.formatted_address == "New York, NY, USA"
end
test "returns error on ZERO_RESULTS" do
Req.Test.stub(Geocoding, fn conn ->
Req.Test.json(conn, %{"status" => "ZERO_RESULTS", "results" => []})
end)
assert {:error, message} = Geocoding.geocode("nonexistent address")
assert message =~ "No results"
end
test "returns error on OVER_QUERY_LIMIT" do
Req.Test.stub(Geocoding, fn conn ->
Req.Test.json(conn, %{"status" => "OVER_QUERY_LIMIT"})
end)
assert {:error, message} = Geocoding.geocode("anywhere")
assert message =~ "quota"
end
test "returns error on REQUEST_DENIED with message" do
Req.Test.stub(Geocoding, fn conn ->
Req.Test.json(conn, %{
"status" => "REQUEST_DENIED",
"error_message" => "API key invalid"
})
end)
assert {:error, message} = Geocoding.geocode("anywhere")
assert message =~ "denied"
assert message =~ "API key invalid"
end
test "returns error on INVALID_REQUEST" do
Req.Test.stub(Geocoding, fn conn ->
Req.Test.json(conn, %{"status" => "INVALID_REQUEST"})
end)
assert {:error, message} = Geocoding.geocode("")
assert message =~ "Invalid request"
end
test "returns error on unknown status" do
Req.Test.stub(Geocoding, fn conn ->
Req.Test.json(conn, %{"status" => "UNKNOWN_ERROR"})
end)
assert {:error, message} = Geocoding.geocode("anywhere")
assert message =~ "UNKNOWN_ERROR"
end
test "returns error when OK but missing geometry" do
Req.Test.stub(Geocoding, fn conn ->
Req.Test.json(conn, %{
"status" => "OK",
"results" => [%{"formatted_address" => "Somewhere"}]
})
end)
assert {:error, message} = Geocoding.geocode("anywhere")
assert message =~ "Invalid response format"
end
test "returns error for unexpected response body" do
Req.Test.stub(Geocoding, fn conn ->
Req.Test.json(conn, %{"unexpected" => "shape"})
end)
assert {:error, message} = Geocoding.geocode("anywhere")
assert message =~ "Unexpected response format"
end
test "returns error on non-200 status" do
Req.Test.stub(Geocoding, fn conn ->
conn
|> Plug.Conn.put_status(500)
|> Req.Test.json(%{"error" => "server error"})
end)
assert {:error, message} = Geocoding.geocode("anywhere")
assert message =~ "Geocoding API error"
assert message =~ "500"
end
test "returns :no_api_key error when key is missing" do
Application.delete_env(:towerops, :google_maps_api_key)
System.delete_env("GOOGLE_MAPS_API_KEY")
assert {:error, :no_api_key} = Geocoding.geocode("anywhere")
end
test "returns :no_api_key error when key is whitespace-only" do
Application.put_env(:towerops, :google_maps_api_key, " ")
System.delete_env("GOOGLE_MAPS_API_KEY")
assert {:error, :no_api_key} = Geocoding.geocode("anywhere")
end
end
end