fix bounds error
This commit is contained in:
parent
86f874194e
commit
445c9899cf
10 changed files with 531 additions and 161 deletions
|
|
@ -19,6 +19,7 @@ import Config
|
|||
# Always start the server in production/docker environments
|
||||
if System.get_env("PHX_SERVER") || config_env() == :prod do
|
||||
config :aprs, AprsWeb.Endpoint, server: true
|
||||
|
||||
IO.puts("Phoenix server enabled - will start HTTP listener")
|
||||
else
|
||||
IO.puts("Phoenix server disabled - no HTTP listener will start")
|
||||
|
|
|
|||
|
|
@ -299,7 +299,10 @@ defmodule Aprs.Is do
|
|||
Logger.info("Successfully stored packet from #{packet.sender}")
|
||||
|
||||
{:error, changeset} ->
|
||||
Logger.error("Failed to store packet from #{inspect(parsed_message.sender)}: #{inspect(changeset.errors)}")
|
||||
Logger.error(
|
||||
"Failed to store packet from #{inspect(parsed_message.sender)}: #{inspect(changeset.errors)}"
|
||||
)
|
||||
|
||||
# Log the problematic attributes for debugging
|
||||
Logger.debug("Packet attributes that failed: #{inspect(attrs)}")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ defmodule Aprs.Packet do
|
|||
if is_valid_coordinates?(lat, lon) do
|
||||
try do
|
||||
location = create_point(lat, lon)
|
||||
|
||||
if location do
|
||||
put_change(changeset, :location, location)
|
||||
else
|
||||
|
|
@ -154,6 +155,7 @@ defmodule Aprs.Packet do
|
|||
rescue
|
||||
error ->
|
||||
require Logger
|
||||
|
||||
Logger.error("Failed to create geometry for lat=#{lat}, lon=#{lon}: #{inspect(error)}")
|
||||
changeset
|
||||
end
|
||||
|
|
|
|||
|
|
@ -74,7 +74,6 @@ defmodule Aprs.Packets do
|
|||
%Packet{}
|
||||
|> Packet.changeset(packet_attrs)
|
||||
|> Repo.insert()
|
||||
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("Exception in store_packet for #{inspect(packet_data[:sender])}: #{inspect(error)}")
|
||||
|
|
|
|||
|
|
@ -200,6 +200,7 @@ defmodule AprsWeb.MapLive.CallsignView do
|
|||
# Helper function to convert string or float to float
|
||||
defp to_float(value) when is_float(value), do: value
|
||||
defp to_float(value) when is_integer(value), do: value * 1.0
|
||||
|
||||
defp to_float(value) when is_binary(value) do
|
||||
case Float.parse(value) do
|
||||
{float_val, _} -> float_val
|
||||
|
|
|
|||
|
|
@ -57,42 +57,45 @@ defmodule AprsWeb.MapLive.Index do
|
|||
)
|
||||
|
||||
if connected?(socket) do
|
||||
IO.puts("Socket is connected, attempting to get IP location")
|
||||
Endpoint.subscribe("aprs_messages")
|
||||
# Get IP-based location on initial load
|
||||
IO.puts("Connect info: #{inspect(socket.private[:connect_info])}")
|
||||
IO.puts("Peer data: #{inspect(socket.private[:connect_info][:peer_data])}")
|
||||
|
||||
ip =
|
||||
case socket.private[:connect_info][:peer_data][:address] do
|
||||
{a, b, c, d} -> "#{a}.#{b}.#{c}.#{d}"
|
||||
{a, b, c, d, e, f, g, h} -> "#{a}:#{b}:#{c}:#{d}:#{e}:#{f}:#{g}:#{h}"
|
||||
_ -> nil
|
||||
end
|
||||
# Only do IP geolocation in non-test environments
|
||||
if Mix.env() != :test do
|
||||
IO.puts("Socket is connected, attempting to get IP location")
|
||||
# Get IP-based location on initial load
|
||||
IO.puts("Connect info: #{inspect(socket.private[:connect_info])}")
|
||||
IO.puts("Peer data: #{inspect(socket.private[:connect_info][:peer_data])}")
|
||||
|
||||
IO.puts("Extracted IP address: #{inspect(ip)}")
|
||||
|
||||
if ip do
|
||||
IO.puts("Starting IP geolocation task for IP: #{ip}")
|
||||
# Start as a separate task and await the result
|
||||
Task.start(fn ->
|
||||
try do
|
||||
get_ip_location(ip)
|
||||
rescue
|
||||
error ->
|
||||
IO.puts("Error in IP geolocation task: #{inspect(error)}")
|
||||
IO.puts("Stacktrace: #{inspect(__STACKTRACE__)}")
|
||||
send(self(), {:ip_location, @default_center})
|
||||
ip =
|
||||
case socket.private[:connect_info][:peer_data][:address] do
|
||||
{a, b, c, d} -> "#{a}.#{b}.#{c}.#{d}"
|
||||
{a, b, c, d, e, f, g, h} -> "#{a}:#{b}:#{c}:#{d}:#{e}:#{f}:#{g}:#{h}"
|
||||
_ -> nil
|
||||
end
|
||||
end)
|
||||
else
|
||||
IO.puts("No IP address found, skipping geolocation")
|
||||
|
||||
# Only attempt IP geolocation if not localhost
|
||||
if ip && !String.starts_with?(ip, "127.") && !String.starts_with?(ip, "::1") do
|
||||
IO.puts("Starting IP geolocation task for IP: #{ip}")
|
||||
# Start as a separate task and await the result
|
||||
Task.start(fn ->
|
||||
try do
|
||||
get_ip_location(ip)
|
||||
rescue
|
||||
error ->
|
||||
IO.puts("Error in IP geolocation task: #{inspect(error)}")
|
||||
IO.puts("Stacktrace: #{inspect(__STACKTRACE__)}")
|
||||
send(self(), {:ip_location, @default_center})
|
||||
end
|
||||
end)
|
||||
else
|
||||
IO.puts("No IP address found, skipping geolocation")
|
||||
end
|
||||
end
|
||||
|
||||
# Schedule regular cleanup of old packets from the map
|
||||
if connected?(socket), do: Process.send_after(self(), :cleanup_old_packets, 60_000)
|
||||
Process.send_after(self(), :cleanup_old_packets, 60_000)
|
||||
# Schedule initialization of replay after a short delay
|
||||
if connected?(socket), do: Process.send_after(self(), :initialize_replay, 2000)
|
||||
Process.send_after(self(), :initialize_replay, 2000)
|
||||
end
|
||||
|
||||
{:ok, socket}
|
||||
|
|
@ -898,6 +901,12 @@ defmodule AprsWeb.MapLive.Index do
|
|||
|
||||
# Helper function to convert string or float to float
|
||||
defp to_float(value) when is_float(value), do: value
|
||||
defp to_float(value) when is_binary(value), do: String.to_float(value)
|
||||
defp to_float(value) when is_integer(value), do: value * 1.0
|
||||
|
||||
defp to_float(value) when is_binary(value) do
|
||||
case Float.parse(value) do
|
||||
{float_val, _} -> float_val
|
||||
:error -> raise ArgumentError, "Invalid float string: #{value}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,130 +0,0 @@
|
|||
#!/usr/bin/env elixir
|
||||
|
||||
# Test script to verify bounds parsing fix in LiveView components
|
||||
# This script tests the to_float helper function to ensure it handles both string and float inputs
|
||||
|
||||
IO.puts("🧪 Testing bounds parsing fix...")
|
||||
|
||||
# Simulate the helper function from the LiveView modules
|
||||
defmodule BoundsParsingTest do
|
||||
# Helper function to convert string or float to float
|
||||
defp to_float(value) when is_float(value), do: value
|
||||
defp to_float(value) when is_binary(value), do: String.to_float(value)
|
||||
defp to_float(value) when is_integer(value), do: value * 1.0
|
||||
|
||||
def test_bounds_parsing do
|
||||
# Test case 1: Float values (the problematic case from the error)
|
||||
float_bounds = %{
|
||||
"north" => 61.897577621605016,
|
||||
"south" => 5.441022303717974,
|
||||
"east" => -34.45312500000001,
|
||||
"west" => -161.54296875000003
|
||||
}
|
||||
|
||||
# Test case 2: String values (the expected case)
|
||||
string_bounds = %{
|
||||
"north" => "61.897577621605016",
|
||||
"south" => "5.441022303717974",
|
||||
"east" => "-34.45312500000001",
|
||||
"west" => "-161.54296875000003"
|
||||
}
|
||||
|
||||
# Test case 3: Integer values
|
||||
integer_bounds = %{
|
||||
"north" => 62,
|
||||
"south" => 5,
|
||||
"east" => -34,
|
||||
"west" => -162
|
||||
}
|
||||
|
||||
# Test case 4: Mixed types
|
||||
mixed_bounds = %{
|
||||
"north" => 61.897577621605016,
|
||||
"south" => "5.441022303717974",
|
||||
"east" => -34,
|
||||
"west" => "-161.54296875000003"
|
||||
}
|
||||
|
||||
test_cases = [
|
||||
{"Float bounds", float_bounds},
|
||||
{"String bounds", string_bounds},
|
||||
{"Integer bounds", integer_bounds},
|
||||
{"Mixed bounds", mixed_bounds}
|
||||
]
|
||||
|
||||
Enum.each(test_cases, fn {name, bounds} ->
|
||||
IO.puts("\n🔍 Testing #{name}:")
|
||||
|
||||
try do
|
||||
normalized_bounds = %{
|
||||
north: to_float(bounds["north"]),
|
||||
south: to_float(bounds["south"]),
|
||||
east: to_float(bounds["east"]),
|
||||
west: to_float(bounds["west"])
|
||||
}
|
||||
|
||||
IO.puts("✅ Success: #{inspect(normalized_bounds)}")
|
||||
rescue
|
||||
error ->
|
||||
IO.puts("❌ Error: #{inspect(error)}")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
def test_replay_speed_parsing do
|
||||
IO.puts("\n🔍 Testing replay speed parsing:")
|
||||
|
||||
test_speeds = [
|
||||
{"Float speed", 1.5},
|
||||
{"String speed", "2.0"},
|
||||
{"Integer speed", 3},
|
||||
{"String integer", "1"}
|
||||
]
|
||||
|
||||
Enum.each(test_speeds, fn {name, speed} ->
|
||||
try do
|
||||
parsed_speed = to_float(speed)
|
||||
IO.puts("✅ #{name}: #{inspect(speed)} -> #{parsed_speed}")
|
||||
rescue
|
||||
error ->
|
||||
IO.puts("❌ #{name} error: #{inspect(error)}")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
# Test edge cases
|
||||
def test_edge_cases do
|
||||
IO.puts("\n🔍 Testing edge cases:")
|
||||
|
||||
edge_cases = [
|
||||
{"Zero float", 0.0},
|
||||
{"Zero string", "0.0"},
|
||||
{"Zero integer", 0},
|
||||
{"Negative float", -123.456},
|
||||
{"Negative string", "-123.456"},
|
||||
{"Large number", 999999.999999}
|
||||
]
|
||||
|
||||
Enum.each(edge_cases, fn {name, value} ->
|
||||
try do
|
||||
result = to_float(value)
|
||||
IO.puts("✅ #{name}: #{inspect(value)} -> #{result}")
|
||||
rescue
|
||||
error ->
|
||||
IO.puts("❌ #{name} error: #{inspect(error)}")
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
# Run the tests
|
||||
BoundsParsingTest.test_bounds_parsing()
|
||||
BoundsParsingTest.test_replay_speed_parsing()
|
||||
BoundsParsingTest.test_edge_cases()
|
||||
|
||||
IO.puts("\n🎉 Bounds parsing test completed!")
|
||||
IO.puts("\n📊 Summary:")
|
||||
IO.puts(" - The to_float helper function handles float, string, and integer inputs")
|
||||
IO.puts(" - This prevents the ArgumentError: not a binary when JavaScript sends float values")
|
||||
IO.puts(" - The LiveView bounds_changed event should now work correctly")
|
||||
IO.puts("\n🚀 The bounds parsing fix is working correctly!")
|
||||
296
test/aprs/geometry_test.exs
Normal file
296
test/aprs/geometry_test.exs
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
defmodule Aprs.GeometryTest do
|
||||
use Aprs.DataCase
|
||||
|
||||
alias Aprs.Packet
|
||||
alias Aprs.Packets
|
||||
alias Geo.PostGIS.Geometry
|
||||
|
||||
describe "PostGIS geometry functionality" do
|
||||
test "create_point/2 creates valid Point geometry" do
|
||||
lat = 32.7767
|
||||
lon = -96.7970
|
||||
|
||||
point = Packet.create_point(lat, lon)
|
||||
|
||||
assert %Geo.Point{} = point
|
||||
assert point.coordinates == {lon, lat}
|
||||
assert point.srid == 4326
|
||||
end
|
||||
|
||||
test "create_point/2 returns nil for invalid coordinates" do
|
||||
# Test invalid latitude
|
||||
assert Packet.create_point(91.0, -96.7970) == nil
|
||||
assert Packet.create_point(-91.0, -96.7970) == nil
|
||||
|
||||
# Test invalid longitude
|
||||
assert Packet.create_point(32.7767, 181.0) == nil
|
||||
assert Packet.create_point(32.7767, -181.0) == nil
|
||||
|
||||
# Test nil values
|
||||
assert Packet.create_point(nil, -96.7970) == nil
|
||||
assert Packet.create_point(32.7767, nil) == nil
|
||||
end
|
||||
|
||||
test "extract_coordinates/1 extracts lat/lon from Point geometry" do
|
||||
point = %Geo.Point{coordinates: {-96.7970, 32.7767}, srid: 4326}
|
||||
|
||||
{lat, lon} = Packet.extract_coordinates(point)
|
||||
|
||||
assert lat == 32.7767
|
||||
assert lon == -96.7970
|
||||
end
|
||||
|
||||
test "extract_coordinates/1 returns {nil, nil} for invalid geometry" do
|
||||
assert Packet.extract_coordinates(nil) == {nil, nil}
|
||||
assert Packet.extract_coordinates("invalid") == {nil, nil}
|
||||
end
|
||||
|
||||
test "packet changeset creates geometry from lat/lon" do
|
||||
attrs = %{
|
||||
base_callsign: "TEST",
|
||||
data_type: "position",
|
||||
destination: "APRS",
|
||||
information_field: "test",
|
||||
path: "WIDE1-1",
|
||||
sender: "TEST-1",
|
||||
ssid: "1",
|
||||
received_at: DateTime.utc_now(),
|
||||
lat: 32.7767,
|
||||
lon: -96.7970
|
||||
}
|
||||
|
||||
changeset = Packet.changeset(%Packet{}, attrs)
|
||||
|
||||
assert changeset.valid?
|
||||
assert get_change(changeset, :location) != nil
|
||||
assert get_change(changeset, :has_position) == true
|
||||
|
||||
location = get_change(changeset, :location)
|
||||
assert %Geo.Point{} = location
|
||||
assert location.coordinates == {-96.7970, 32.7767}
|
||||
end
|
||||
|
||||
test "packet changeset handles invalid coordinates gracefully" do
|
||||
attrs = %{
|
||||
base_callsign: "TEST",
|
||||
data_type: "position",
|
||||
destination: "APRS",
|
||||
information_field: "test",
|
||||
path: "WIDE1-1",
|
||||
sender: "TEST-1",
|
||||
ssid: "1",
|
||||
received_at: DateTime.utc_now(),
|
||||
# Invalid latitude
|
||||
lat: 91.0,
|
||||
lon: -96.7970
|
||||
}
|
||||
|
||||
changeset = Packet.changeset(%Packet{}, attrs)
|
||||
|
||||
# Should still be valid, just without location
|
||||
assert changeset.valid?
|
||||
assert get_change(changeset, :location) == nil
|
||||
assert get_change(changeset, :has_position) != true
|
||||
end
|
||||
|
||||
test "store_packet/1 successfully stores packet with geometry" do
|
||||
attrs = %{
|
||||
base_callsign: "TEST",
|
||||
data_type: "position",
|
||||
destination: "APRS",
|
||||
information_field: "!3216.46N/09647.82W>Test packet",
|
||||
path: "WIDE1-1,WIDE2-1",
|
||||
sender: "TEST-1",
|
||||
ssid: "1",
|
||||
received_at: DateTime.utc_now(),
|
||||
lat: 32.2743,
|
||||
lon: -96.7970,
|
||||
has_position: true,
|
||||
region: "32.3,-96.8",
|
||||
raw_packet: "TEST-1>APRS,WIDE1-1,WIDE2-1:!3216.46N/09647.82W>Test packet"
|
||||
}
|
||||
|
||||
assert {:ok, packet} = Packets.store_packet(attrs)
|
||||
assert packet.sender == "TEST-1"
|
||||
assert packet.has_position == true
|
||||
assert packet.location != nil
|
||||
assert %Geo.Point{} = packet.location
|
||||
assert packet.location.coordinates == {-96.7970, 32.2743}
|
||||
end
|
||||
|
||||
test "store_packet/1 handles packet without position data" do
|
||||
attrs = %{
|
||||
base_callsign: "TEST",
|
||||
data_type: "message",
|
||||
destination: "APRS",
|
||||
information_field: ":TEST-2 :Hello world",
|
||||
path: "WIDE1-1",
|
||||
sender: "TEST-1",
|
||||
ssid: "1",
|
||||
received_at: DateTime.utc_now(),
|
||||
raw_packet: "TEST-1>APRS,WIDE1-1::TEST-2 :Hello world"
|
||||
}
|
||||
|
||||
assert {:ok, packet} = Packets.store_packet(attrs)
|
||||
assert packet.sender == "TEST-1"
|
||||
assert packet.has_position == false
|
||||
assert packet.location == nil
|
||||
end
|
||||
|
||||
test "store_packet/1 handles coordinate validation errors gracefully" do
|
||||
attrs = %{
|
||||
base_callsign: "TEST",
|
||||
data_type: "position",
|
||||
destination: "APRS",
|
||||
information_field: "test",
|
||||
path: "WIDE1-1",
|
||||
sender: "TEST-1",
|
||||
ssid: "1",
|
||||
received_at: DateTime.utc_now(),
|
||||
# Invalid latitude
|
||||
lat: 200.0,
|
||||
lon: -96.7970,
|
||||
raw_packet: "TEST-1>APRS,WIDE1-1:test"
|
||||
}
|
||||
|
||||
# Should not crash, but should handle gracefully
|
||||
assert {:ok, packet} = Packets.store_packet(attrs)
|
||||
assert packet.sender == "TEST-1"
|
||||
assert packet.has_position == false
|
||||
assert packet.location == nil
|
||||
end
|
||||
|
||||
test "Geo.PostGIS.Geometry cast works with Point" do
|
||||
point = %Geo.Point{coordinates: {-96.7970, 32.7767}, srid: 4326}
|
||||
|
||||
assert {:ok, ^point} = Geometry.cast(point)
|
||||
end
|
||||
|
||||
test "Geo.PostGIS.Geometry cast works with coordinate tuple" do
|
||||
coords = {-96.7970, 32.7767}
|
||||
|
||||
# PostGIS geometry casting may not support tuples directly
|
||||
# Instead test creating a point manually
|
||||
point = %Geo.Point{coordinates: coords, srid: 4326}
|
||||
assert {:ok, ^point} = Geometry.cast(point)
|
||||
end
|
||||
|
||||
test "packet lat/lon helper functions work correctly" do
|
||||
packet = %Packet{
|
||||
location: %Geo.Point{coordinates: {-96.7970, 32.7767}, srid: 4326}
|
||||
}
|
||||
|
||||
assert Packet.lat(packet) == 32.7767
|
||||
assert Packet.lon(packet) == -96.7970
|
||||
end
|
||||
|
||||
test "packet lat/lon helpers return nil for packets without location" do
|
||||
packet = %Packet{location: nil}
|
||||
|
||||
assert Packet.lat(packet) == nil
|
||||
assert Packet.lon(packet) == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "coordinate conversion and validation" do
|
||||
test "handles various coordinate formats" do
|
||||
# Test float coordinates
|
||||
assert Packet.create_point(32.7767, -96.7970) != nil
|
||||
|
||||
# Test integer coordinates
|
||||
assert Packet.create_point(33, -97) != nil
|
||||
|
||||
# Test boundary values
|
||||
assert Packet.create_point(90.0, 180.0) != nil
|
||||
assert Packet.create_point(-90.0, -180.0) != nil
|
||||
|
||||
# Test just inside boundaries
|
||||
assert Packet.create_point(89.9999, 179.9999) != nil
|
||||
assert Packet.create_point(-89.9999, -179.9999) != nil
|
||||
end
|
||||
|
||||
test "rejects coordinates outside valid ranges" do
|
||||
# Test latitude boundaries
|
||||
assert Packet.create_point(90.0001, 0.0) == nil
|
||||
assert Packet.create_point(-90.0001, 0.0) == nil
|
||||
|
||||
# Test longitude boundaries
|
||||
assert Packet.create_point(0.0, 180.0001) == nil
|
||||
assert Packet.create_point(0.0, -180.0001) == nil
|
||||
end
|
||||
|
||||
test "handles edge case coordinates" do
|
||||
# Test zero coordinates
|
||||
assert Packet.create_point(0.0, 0.0) != nil
|
||||
|
||||
# Test very small coordinates
|
||||
assert Packet.create_point(0.000001, 0.000001) != nil
|
||||
|
||||
# Test coordinates near boundaries
|
||||
assert Packet.create_point(89.999999, 179.999999) != nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "packet storage with different position formats" do
|
||||
test "stores packet with MicE-like data structure" do
|
||||
# Test packet storage that would involve MicE conversion
|
||||
attrs = %{
|
||||
base_callsign: "TEST",
|
||||
data_type: "position",
|
||||
destination: "APRS",
|
||||
information_field: "test",
|
||||
path: "WIDE1-1",
|
||||
sender: "TEST-1",
|
||||
ssid: "1",
|
||||
received_at: DateTime.utc_now(),
|
||||
# Pre-converted coordinates
|
||||
lat: 32.7767,
|
||||
lon: -96.7970,
|
||||
raw_packet: "TEST-1>APRS,WIDE1-1:test"
|
||||
}
|
||||
|
||||
assert {:ok, packet} = Packets.store_packet(attrs)
|
||||
assert packet.sender == "TEST-1"
|
||||
assert packet.has_position == true
|
||||
assert packet.location != nil
|
||||
end
|
||||
|
||||
test "stores packet with standard position data" do
|
||||
attrs = %{
|
||||
base_callsign: "TEST",
|
||||
data_type: "position",
|
||||
destination: "APRS",
|
||||
information_field: "test",
|
||||
path: "WIDE1-1",
|
||||
sender: "TEST-2",
|
||||
ssid: "2",
|
||||
received_at: DateTime.utc_now(),
|
||||
lat: 32.7767,
|
||||
lon: -96.7970,
|
||||
raw_packet: "TEST-2>APRS,WIDE1-1:test"
|
||||
}
|
||||
|
||||
assert {:ok, packet} = Packets.store_packet(attrs)
|
||||
assert packet.has_position == true
|
||||
assert %Geo.Point{} = packet.location
|
||||
end
|
||||
|
||||
test "stores packet without position data" do
|
||||
attrs = %{
|
||||
base_callsign: "TEST",
|
||||
data_type: "message",
|
||||
destination: "APRS",
|
||||
information_field: ":TEST-2 :Hello",
|
||||
path: "WIDE1-1",
|
||||
sender: "TEST-3",
|
||||
ssid: "3",
|
||||
received_at: DateTime.utc_now(),
|
||||
raw_packet: "TEST-3>APRS,WIDE1-1::TEST-2 :Hello"
|
||||
}
|
||||
|
||||
assert {:ok, packet} = Packets.store_packet(attrs)
|
||||
assert packet.has_position == false
|
||||
assert packet.location == nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -66,5 +66,82 @@ defmodule AprsWeb.MapLive.CallsignViewTest do
|
|||
|
||||
assert page_title(view) =~ "APRS Map - W5ISP-9"
|
||||
end
|
||||
|
||||
test "handles bounds_changed event with float values", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/W5ISP-9")
|
||||
|
||||
# Simulate JavaScript sending float values (the problematic case)
|
||||
bounds_params = %{
|
||||
"bounds" => %{
|
||||
"north" => 61.897577621605016,
|
||||
"south" => 5.441022303717974,
|
||||
"east" => -34.45312500000001,
|
||||
"west" => -161.54296875000003
|
||||
}
|
||||
}
|
||||
|
||||
# This should not crash with ArgumentError: not a binary
|
||||
assert render_hook(view, "bounds_changed", bounds_params)
|
||||
end
|
||||
|
||||
test "handles bounds_changed event with string values", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/W5ISP-9")
|
||||
|
||||
# Simulate JavaScript sending string values (expected case)
|
||||
bounds_params = %{
|
||||
"bounds" => %{
|
||||
"north" => "61.897577621605016",
|
||||
"south" => "5.441022303717974",
|
||||
"east" => "-34.45312500000001",
|
||||
"west" => "-161.54296875000003"
|
||||
}
|
||||
}
|
||||
|
||||
assert render_hook(view, "bounds_changed", bounds_params)
|
||||
end
|
||||
|
||||
test "handles bounds_changed event with mixed value types", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/W5ISP-9")
|
||||
|
||||
# Test mixed types (float, string, integer)
|
||||
bounds_params = %{
|
||||
"bounds" => %{
|
||||
# float
|
||||
"north" => 61.897577621605016,
|
||||
# string
|
||||
"south" => "5.441022303717974",
|
||||
# integer
|
||||
"east" => -34,
|
||||
# string
|
||||
"west" => "-161.54296875000003"
|
||||
}
|
||||
}
|
||||
|
||||
assert render_hook(view, "bounds_changed", bounds_params)
|
||||
end
|
||||
|
||||
test "handles adjust_replay_speed event with float values", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/W5ISP-9")
|
||||
|
||||
# Test with float speed value
|
||||
speed_params = %{"speed" => 1.5}
|
||||
assert render_hook(view, "adjust_replay_speed", speed_params)
|
||||
end
|
||||
|
||||
test "handles adjust_replay_speed event with string values", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/W5ISP-9")
|
||||
|
||||
# Test with string speed value
|
||||
speed_params = %{"speed" => "2.0"}
|
||||
assert render_hook(view, "adjust_replay_speed", speed_params)
|
||||
end
|
||||
|
||||
test "handles adjust_replay_speed event with integer values", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/W5ISP-9")
|
||||
|
||||
# Test with integer speed value
|
||||
speed_params = %{"speed" => 3}
|
||||
assert render_hook(view, "adjust_replay_speed", speed_params)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
112
test/aprs_web/live/map_live/index_test.exs
Normal file
112
test/aprs_web/live/map_live/index_test.exs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
defmodule AprsWeb.MapLive.IndexTest do
|
||||
use AprsWeb.ConnCase
|
||||
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
describe "Index" do
|
||||
test "renders map view", %{conn: conn} do
|
||||
{:ok, view, html} = live(conn, "/")
|
||||
|
||||
assert html =~ "APRS Map"
|
||||
assert has_element?(view, "#aprs-map")
|
||||
end
|
||||
|
||||
test "handles bounds_changed event with float values", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/")
|
||||
|
||||
# Simulate JavaScript sending float values (the problematic case)
|
||||
bounds_params = %{
|
||||
"bounds" => %{
|
||||
"north" => 61.897577621605016,
|
||||
"south" => 5.441022303717974,
|
||||
"east" => -34.45312500000001,
|
||||
"west" => -161.54296875000003
|
||||
}
|
||||
}
|
||||
|
||||
# This should not crash with ArgumentError: not a binary
|
||||
assert render_hook(view, "bounds_changed", bounds_params)
|
||||
end
|
||||
|
||||
test "handles bounds_changed event with string values", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/")
|
||||
|
||||
# Simulate JavaScript sending string values (expected case)
|
||||
bounds_params = %{
|
||||
"bounds" => %{
|
||||
"north" => "61.897577621605016",
|
||||
"south" => "5.441022303717974",
|
||||
"east" => "-34.45312500000001",
|
||||
"west" => "-161.54296875000003"
|
||||
}
|
||||
}
|
||||
|
||||
assert render_hook(view, "bounds_changed", bounds_params)
|
||||
end
|
||||
|
||||
test "handles bounds_changed event with mixed value types", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/")
|
||||
|
||||
# Test mixed types (float, string, integer)
|
||||
bounds_params = %{
|
||||
"bounds" => %{
|
||||
# float
|
||||
"north" => 61.897577621605016,
|
||||
# string
|
||||
"south" => "5.441022303717974",
|
||||
# integer
|
||||
"east" => -34,
|
||||
# string
|
||||
"west" => "-161.54296875000003"
|
||||
}
|
||||
}
|
||||
|
||||
assert render_hook(view, "bounds_changed", bounds_params)
|
||||
end
|
||||
|
||||
test "handles adjust_replay_speed event with float values", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/")
|
||||
|
||||
# Test with float speed value
|
||||
speed_params = %{"speed" => 1.5}
|
||||
assert render_hook(view, "adjust_replay_speed", speed_params)
|
||||
end
|
||||
|
||||
test "handles adjust_replay_speed event with string values", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/")
|
||||
|
||||
# Test with string speed value
|
||||
speed_params = %{"speed" => "2.0"}
|
||||
assert render_hook(view, "adjust_replay_speed", speed_params)
|
||||
end
|
||||
|
||||
test "handles adjust_replay_speed event with integer values", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/")
|
||||
|
||||
# Test with integer speed value
|
||||
speed_params = %{"speed" => 3}
|
||||
assert render_hook(view, "adjust_replay_speed", speed_params)
|
||||
end
|
||||
|
||||
test "handles adjust_replay_speed event with integer string values", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/")
|
||||
|
||||
# Test with integer string value (should work with improved Float.parse)
|
||||
speed_params = %{"speed" => "1"}
|
||||
assert render_hook(view, "adjust_replay_speed", speed_params)
|
||||
end
|
||||
|
||||
test "sets correct page title", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/")
|
||||
|
||||
assert page_title(view) =~ "APRS Map"
|
||||
end
|
||||
|
||||
test "handles map_ready event", %{conn: conn} do
|
||||
{:ok, view, _html} = live(conn, "/")
|
||||
|
||||
# Simulate map initialization
|
||||
assert render_hook(view, "map_ready", %{})
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue