296 lines
8.9 KiB
Elixir
296 lines
8.9 KiB
Elixir
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_in_delta elem(packet.location.coordinates, 1), 32.2743, 0.0001
|
|
assert_in_delta elem(packet.location.coordinates, 0), -96.7970, 0.0001
|
|
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
|