defmodule AprsmeWeb.MapLive.DataBuilderTest do use Aprsme.DataCase, async: true alias AprsmeWeb.MapLive.DataBuilder describe "display name for APRS objects and items" do # credo:disable-for-next-line Jump.CredoChecks.TestHasNoAssertions 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) end # credo:disable-for-next-line Jump.CredoChecks.TestHasNoAssertions 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) end # credo:disable-for-next-line Jump.CredoChecks.TestHasNoAssertions # credo:disable-for-next-line Jump.CredoChecks.TestHasNoAssertions 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) 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 # result is not nil - verified by subsequent key access["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) # result is not nil - verified by subsequent key access # Map label shows object name for objects # result is not nil - verified by subsequent key access["callsign"] == "P-K5SGD" # Grouping also uses object name # result is not nil - verified by subsequent key access["callsign_group"] == "P-K5SGD" # Symbol HTML should show object name # result is not nil - verified by subsequent key access["symbol_html"] =~ "P-K5SGD" refute result["symbol_html"] =~ "DB0SDA" # credo:disable-for-next-line Jump.CredoChecks.TestHasNoAssertions end # credo:disable-for-next-line Jump.CredoChecks.TestHasNoAssertions 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) 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) # result is not nil - verified by subsequent key access # result is not nil - verified by subsequent key access["is_most_recent_for_callsign"] == true # Most recent should NOT use the red dot # credo:disable-for-next-line Jump.CredoChecks.TestHasNoAssertions refute result["symbol_html"] =~ "#FF6B6B" end # credo:disable-for-next-line Jump.CredoChecks.TestHasNoAssertions 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) end # credo:disable-for-next-line Jump.CredoChecks.TestHasNoAssertions 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) 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