aprs.me/test/aprsme_web/live/map_live/movement_test.exs
Graham McIntire b065404803
Fix credo warnings and ensure clean compilation
- Renamed predicate functions to follow Elixir conventions:
  - is_finite? → finite?
  - is_finite_number? → finite_number?
  - is_finite_float? → finite_float?
- Fixed all function returns to ensure proper nil handling
- Applied mix format to all files
- All tests pass with no compilation warnings

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-14 10:25:01 -05:00

186 lines
5.1 KiB
Elixir

defmodule AprsmeWeb.MapLive.MovementTest do
use AprsmeWeb.ConnCase, async: false
import Mox
import Phoenix.LiveViewTest
alias Aprsme.GeoUtils
setup :verify_on_exit!
describe "GPS drift filtering" do
setup do
# Mock the Packets module to return empty results for historical queries
stub(Aprsme.PacketsMock, :get_recent_packets_optimized, fn _args -> [] end)
:ok
end
test "does not update marker for GPS drift", %{conn: conn} do
# Start with initial location
{:ok, view, _html} = live(conn, "/")
# First update the map state to set zoom level
assert render_hook(view, "update_map_state", %{
"center" => %{"lat" => 33.16961, "lng" => -96.4921},
"zoom" => 9
})
# Then update bounds
bounds_params = %{
"bounds" => %{
"north" => 33.18,
"south" => 33.16,
"east" => -96.48,
"west" => -96.50
}
}
assert render_hook(view, "bounds_changed", bounds_params)
:timer.sleep(100)
# Simulate initial packet
initial_packet = %{
"id" => "TEST-1",
"sender" => "TEST-1",
"base_callsign" => "TEST",
"lat" => 33.16961,
"lon" => -96.4921,
"has_position" => true,
"received_at" => DateTime.utc_now()
}
send(view.pid, {:postgres_packet, initial_packet})
# Wait for the initial packet to be processed
:timer.sleep(100)
# Simulate GPS drift (5 meters movement)
drift_packet = %{
"id" => "TEST-1",
"sender" => "TEST-1",
"base_callsign" => "TEST",
# About 5 meters north
"lat" => 33.169655,
"lon" => -96.4921,
"has_position" => true,
"received_at" => DateTime.utc_now()
}
# Send the drift packet
send(view.pid, {:postgres_packet, drift_packet})
# The view should not push a new_packet event for GPS drift
refute_push_event(view, "new_packet", %{id: "TEST-1"}, 200)
end
test "updates marker for significant movement", %{conn: conn} do
# Start with initial location at a zoom level that shows individual markers
{:ok, view, _html} = live(conn, "/?z=15")
# Notify the map is ready
assert render_hook(view, "map_ready", %{})
# Update the map state to zoom level 15 (individual markers)
assert render_hook(view, "update_map_state", %{
"center" => %{"lat" => 33.16961, "lng" => -96.4921},
"zoom" => 15
})
# Set bounds to ensure packets are visible
bounds_params = %{
"bounds" => %{
"north" => 33.18,
"south" => 33.16,
"east" => -96.48,
"west" => -96.50
}
}
assert render_hook(view, "bounds_changed", bounds_params)
# Wait for initial load to complete
:timer.sleep(500)
# Clear any events from initial load
flush_push_events(view)
# Simulate initial packet
initial_packet = %{
"id" => "TEST-2",
"sender" => "TEST-2",
"base_callsign" => "TEST",
"lat" => 33.16961,
"lon" => -96.4921,
"has_position" => true,
"received_at" => DateTime.utc_now()
}
send(view.pid, {:postgres_packet, initial_packet})
# Wait for the initial packet to be processed
:timer.sleep(100)
# Should receive new_packet for the initial packet
assert_push_event(view, "new_packet", %{}, 1000)
# Simulate significant movement (20+ meters)
moved_packet = %{
"id" => "TEST-2",
"sender" => "TEST-2",
"base_callsign" => "TEST",
# About 20 meters north
"lat" => 33.1698,
"lon" => -96.4921,
"has_position" => true,
"received_at" => DateTime.utc_now()
}
# Send the moved packet
send(view.pid, {:postgres_packet, moved_packet})
# Wait a bit for processing
:timer.sleep(100)
# The view should push a new_packet event for significant movement
assert_push_event(view, "new_packet", %{}, 1000)
end
defp flush_push_events(view) do
receive do
{ref, {:push_event, _, _}} when is_reference(ref) and ref == view.ref ->
flush_push_events(view)
after
0 -> :ok
end
end
end
describe "distance calculations" do
test "calculates correct distances for GPS drift scenarios" do
# Example from the URL provided
lat1 = 33.16961
lon1 = -96.4921
# Tiny drift - should be filtered
lat2 = 33.169615
lon2 = -96.492095
distance = GeoUtils.haversine_distance(lat1, lon1, lat2, lon2)
# Less than 10 meters
assert distance < 10
# Slightly larger drift
lat3 = 33.16965
lon3 = -96.4921
distance2 = GeoUtils.haversine_distance(lat1, lon1, lat3, lon3)
# Still GPS drift range
assert distance2 < 10
# Actual movement
lat4 = 33.17000
lon4 = -96.4921
distance3 = GeoUtils.haversine_distance(lat1, lon1, lat4, lon4)
# Significant movement
assert distance3 > 20
end
end
end