Objects and items now display with their own names on the map instead of the originating station's callsign. This prevents confusion where stations creating objects (like repeaters) appear at multiple locations. For example, CALGRY creates repeater objects (147.06-WC, 146.85-NH) which were appearing on the map labeled as "CALGRY" at the repeater locations instead of showing the actual object names. Changes: - Updated map_label() to return object_name for object packets - Updated map_label() to return item_name for item packets - Position packets continue to show the sender callsign - Updated tests to expect object/item names instead of sender This matches APRS.fi behavior where objects are displayed separately from their originating station.
376 lines
11 KiB
Elixir
376 lines
11 KiB
Elixir
defmodule AprsmeWeb.MapLive.DataBuilderTest do
|
|
use Aprsme.DataCase, async: true
|
|
|
|
alias AprsmeWeb.MapLive.DataBuilder
|
|
|
|
describe "display name for APRS objects and items" do
|
|
test "uses sender for map label but object_name for grouping when packet is an object" do
|
|
packet = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "DB0SDA",
|
|
base_callsign: "DB0SDA",
|
|
ssid: "",
|
|
object_name: "P-K5SGD",
|
|
is_object: true,
|
|
is_item: false,
|
|
lat: 33.169333,
|
|
lon: -96.492167,
|
|
data_type: "object",
|
|
received_at: DateTime.utc_now(),
|
|
symbol_table_id: "P",
|
|
symbol_code: "#",
|
|
comment: "DAPNET POCSAG Transmitter",
|
|
has_position: true,
|
|
path: "TCPIP*,qAC,FIFTH"
|
|
}
|
|
|
|
result = DataBuilder.build_packet_data(packet, true)
|
|
|
|
assert result
|
|
# Map label shows object name for objects
|
|
assert result["callsign"] == "P-K5SGD"
|
|
# Grouping also uses object name
|
|
assert result["callsign_group"] == "P-K5SGD"
|
|
end
|
|
|
|
test "uses sender for map label but item_name for grouping when packet is an item" do
|
|
packet = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "N0CALL",
|
|
base_callsign: "N0CALL",
|
|
ssid: "",
|
|
item_name: "REPEATER1",
|
|
is_item: true,
|
|
is_object: false,
|
|
lat: 40.0,
|
|
lon: -105.0,
|
|
data_type: "item",
|
|
received_at: DateTime.utc_now(),
|
|
symbol_table_id: "/",
|
|
symbol_code: "r",
|
|
comment: "Some repeater",
|
|
has_position: true,
|
|
path: "WIDE1-1"
|
|
}
|
|
|
|
result = DataBuilder.build_packet_data(packet, true)
|
|
|
|
assert result
|
|
# Map label shows item name for items
|
|
assert result["callsign"] == "REPEATER1"
|
|
# Grouping also uses item name
|
|
assert result["callsign_group"] == "REPEATER1"
|
|
end
|
|
|
|
test "falls back to sender when no object_name or item_name" do
|
|
packet = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "K5SGD-Y",
|
|
base_callsign: "K5SGD",
|
|
ssid: "Y",
|
|
object_name: nil,
|
|
item_name: nil,
|
|
is_object: false,
|
|
is_item: false,
|
|
lat: 33.169333,
|
|
lon: -96.492167,
|
|
data_type: "position",
|
|
received_at: DateTime.utc_now(),
|
|
symbol_table_id: "/",
|
|
symbol_code: ">",
|
|
comment: "Test station",
|
|
has_position: true,
|
|
path: "WIDE1-1"
|
|
}
|
|
|
|
result = DataBuilder.build_packet_data(packet, true)
|
|
|
|
assert result
|
|
assert result["callsign"] == "K5SGD-Y"
|
|
end
|
|
|
|
test "uses sender in popup for object packets" do
|
|
packet = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "DB0SDA",
|
|
base_callsign: "DB0SDA",
|
|
ssid: "",
|
|
object_name: "P-K5SGD",
|
|
is_object: true,
|
|
is_item: false,
|
|
lat: 33.169333,
|
|
lon: -96.492167,
|
|
data_type: "object",
|
|
received_at: DateTime.utc_now(),
|
|
symbol_table_id: "P",
|
|
symbol_code: "#",
|
|
comment: "DAPNET POCSAG Transmitter",
|
|
has_position: true,
|
|
path: "TCPIP*,qAC,FIFTH"
|
|
}
|
|
|
|
result = DataBuilder.build_packet_data(packet, true)
|
|
|
|
# Popup now shows object name for objects
|
|
assert result["popup"] =~ "P-K5SGD"
|
|
refute result["popup"] =~ "DB0SDA"
|
|
end
|
|
|
|
test "build_minimal_packet_data uses sender for map label but object_name for grouping" do
|
|
packet = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "DB0SDA",
|
|
base_callsign: "DB0SDA",
|
|
ssid: "",
|
|
object_name: "P-K5SGD",
|
|
is_object: true,
|
|
is_item: false,
|
|
lat: 33.169333,
|
|
lon: -96.492167,
|
|
data_type: "object",
|
|
received_at: DateTime.utc_now(),
|
|
symbol_table_id: "P",
|
|
symbol_code: "#",
|
|
comment: "DAPNET POCSAG Transmitter",
|
|
has_position: true,
|
|
path: "TCPIP*,qAC,FIFTH"
|
|
}
|
|
|
|
result = DataBuilder.build_minimal_packet_data(packet, true, false)
|
|
|
|
assert result
|
|
# Map label shows object name for objects
|
|
assert result["callsign"] == "P-K5SGD"
|
|
# Grouping also uses object name
|
|
assert result["callsign_group"] == "P-K5SGD"
|
|
# Symbol HTML should show object name
|
|
assert result["symbol_html"] =~ "P-K5SGD"
|
|
refute result["symbol_html"] =~ "DB0SDA"
|
|
end
|
|
|
|
test "build_minimal_packet_data uses red dot HTML for historical (non-most-recent) packets" do
|
|
packet = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "K5GVL-10",
|
|
base_callsign: "K5GVL",
|
|
ssid: "10",
|
|
lat: 33.1,
|
|
lon: -96.5,
|
|
received_at: DateTime.utc_now(),
|
|
symbol_table_id: "/",
|
|
symbol_code: "-",
|
|
comment: "Test",
|
|
path: "WIDE1-1"
|
|
}
|
|
|
|
result = DataBuilder.build_minimal_packet_data(packet, false, false)
|
|
|
|
assert result
|
|
assert result["historical"] == true
|
|
# Historical dot should use inline red dot HTML, not a full symbol
|
|
assert result["symbol_html"] =~ "background-color"
|
|
assert result["symbol_html"] =~ "#FF6B6B"
|
|
end
|
|
|
|
test "build_minimal_packet_data uses full symbol for most-recent packets" do
|
|
packet = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "K5GVL-10",
|
|
base_callsign: "K5GVL",
|
|
ssid: "10",
|
|
lat: 33.1,
|
|
lon: -96.5,
|
|
received_at: DateTime.utc_now(),
|
|
symbol_table_id: "/",
|
|
symbol_code: "-",
|
|
comment: "Test",
|
|
path: "WIDE1-1"
|
|
}
|
|
|
|
result = DataBuilder.build_minimal_packet_data(packet, true, false)
|
|
|
|
assert result
|
|
assert result["is_most_recent_for_callsign"] == true
|
|
# Most recent should NOT use the red dot
|
|
refute result["symbol_html"] =~ "#FF6B6B"
|
|
end
|
|
|
|
test "build_minimal_packet_data includes callsign_group field" do
|
|
packet = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "K5GVL-10",
|
|
base_callsign: "K5GVL",
|
|
ssid: "10",
|
|
lat: 33.1,
|
|
lon: -96.5,
|
|
received_at: DateTime.utc_now(),
|
|
symbol_table_id: "/",
|
|
symbol_code: "-",
|
|
comment: "Test",
|
|
path: "WIDE1-1"
|
|
}
|
|
|
|
result = DataBuilder.build_minimal_packet_data(packet, true, false)
|
|
|
|
assert result["callsign_group"] == "K5GVL-10"
|
|
end
|
|
|
|
test "build_packet_data includes callsign_group field" do
|
|
packet = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "K5GVL-10",
|
|
base_callsign: "K5GVL",
|
|
ssid: "10",
|
|
lat: 33.1,
|
|
lon: -96.5,
|
|
received_at: DateTime.utc_now(),
|
|
symbol_table_id: "/",
|
|
symbol_code: "-",
|
|
comment: "Test",
|
|
data_type: "position",
|
|
path: "WIDE1-1"
|
|
}
|
|
|
|
result = DataBuilder.build_packet_data(packet, true)
|
|
|
|
assert result["callsign_group"] == "K5GVL-10"
|
|
end
|
|
|
|
test "build_packet_data_list output is sorted by callsign group then chronologically" do
|
|
now = DateTime.utc_now()
|
|
|
|
# Two callsigns, each with 2 packets at different times
|
|
packets = [
|
|
%{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "ZZZ-1",
|
|
base_callsign: "ZZZ",
|
|
ssid: "1",
|
|
lat: 33.1,
|
|
lon: -96.5,
|
|
received_at: DateTime.add(now, -300, :second),
|
|
symbol_table_id: "/",
|
|
symbol_code: "-",
|
|
comment: "",
|
|
path: ""
|
|
},
|
|
%{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "AAA-1",
|
|
base_callsign: "AAA",
|
|
ssid: "1",
|
|
lat: 34.0,
|
|
lon: -97.0,
|
|
received_at: now,
|
|
symbol_table_id: "/",
|
|
symbol_code: ">",
|
|
comment: "",
|
|
path: ""
|
|
},
|
|
%{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "ZZZ-1",
|
|
base_callsign: "ZZZ",
|
|
ssid: "1",
|
|
lat: 33.2,
|
|
lon: -96.4,
|
|
received_at: now,
|
|
symbol_table_id: "/",
|
|
symbol_code: "-",
|
|
comment: "",
|
|
path: ""
|
|
}
|
|
]
|
|
|
|
results = DataBuilder.build_packet_data_list(packets)
|
|
|
|
# All results should have callsign_group
|
|
assert Enum.all?(results, &Map.has_key?(&1, "callsign_group"))
|
|
|
|
# Packets should be grouped by callsign (all AAA together, all ZZZ together)
|
|
callsigns = Enum.map(results, & &1["callsign"])
|
|
groups = Enum.chunk_by(callsigns, & &1)
|
|
# Each group should contain only one unique callsign
|
|
assert Enum.all?(groups, fn group -> length(Enum.uniq(group)) == 1 end)
|
|
end
|
|
|
|
test "build_packet_data_list groups by object_name for objects" do
|
|
now = DateTime.utc_now()
|
|
earlier = DateTime.add(now, -600, :second)
|
|
|
|
object_packet_1 = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "DB0SDA",
|
|
base_callsign: "DB0SDA",
|
|
ssid: "",
|
|
object_name: "P-K5SGD",
|
|
is_object: true,
|
|
is_item: false,
|
|
lat: 33.169333,
|
|
lon: -96.492167,
|
|
data_type: "object",
|
|
received_at: now,
|
|
symbol_table_id: "P",
|
|
symbol_code: "#",
|
|
comment: "DAPNET POCSAG Transmitter",
|
|
has_position: true,
|
|
path: "TCPIP*,qAC,FIFTH"
|
|
}
|
|
|
|
object_packet_2 = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "DB0SDA",
|
|
base_callsign: "DB0SDA",
|
|
ssid: "",
|
|
object_name: "P-K5SGD",
|
|
is_object: true,
|
|
is_item: false,
|
|
lat: 33.170,
|
|
lon: -96.493,
|
|
data_type: "object",
|
|
received_at: earlier,
|
|
symbol_table_id: "P",
|
|
symbol_code: "#",
|
|
comment: "DAPNET POCSAG Transmitter",
|
|
has_position: true,
|
|
path: "TCPIP*,qAC,FIFTH"
|
|
}
|
|
|
|
results = DataBuilder.build_packet_data_list([object_packet_1, object_packet_2])
|
|
|
|
# Map labels should show object name
|
|
callsigns = Enum.map(results, & &1["callsign"])
|
|
assert Enum.all?(callsigns, &(&1 == "P-K5SGD"))
|
|
|
|
# But grouping should be by object name
|
|
groups = Enum.map(results, & &1["callsign_group"])
|
|
assert Enum.all?(groups, &(&1 == "P-K5SGD"))
|
|
end
|
|
|
|
test "build_simple_popup shows sender for object packets" do
|
|
packet = %{
|
|
id: Ecto.UUID.generate(),
|
|
sender: "WA0YMH-2",
|
|
base_callsign: "WA0YMH",
|
|
ssid: "2",
|
|
object_name: "X3234025",
|
|
is_object: true,
|
|
is_item: false,
|
|
lat: 33.251833,
|
|
lon: -95.719833,
|
|
data_type: "object",
|
|
received_at: DateTime.utc_now(),
|
|
symbol_table_id: "/",
|
|
symbol_code: "O",
|
|
comment: "Clb=5.9m/s t=-58.5C 404.800MHz Type=RS41-NG rdzTTGOsonde",
|
|
has_position: true,
|
|
path: "TCPIP*,qAR,WA0YMH-2"
|
|
}
|
|
|
|
popup = DataBuilder.build_simple_popup(packet, false)
|
|
|
|
assert popup =~ "X3234025"
|
|
refute popup =~ "WA0YMH-2"
|
|
end
|
|
end
|
|
end
|