defmodule AprsmeWeb.Live.SharedPacketHandlerTest do use ExUnit.Case, async: true alias AprsmeWeb.Live.SharedPacketHandler defp socket, do: %Phoenix.LiveView.Socket{assigns: %{__changed__: %{}}} defp allow_all, do: fn _packet, _socket -> true end defp allow_none, do: fn _packet, _socket -> false end defp record_process(ref), do: fn packet, s -> send(ref, {:processed, packet}) {:noreply, s} end describe "handle_packet_update/3" do test "skips processing when filter returns false" do socket = socket() {result, ^socket} = {nil, socket} _ = result assert {:noreply, ^socket} = SharedPacketHandler.handle_packet_update( %{sender: "K5ABC"}, socket, filter_fn: allow_none(), process_fn: record_process(self()) ) refute_received {:processed, _} end test "processes and enriches packet when filter returns true" do {:noreply, _} = SharedPacketHandler.handle_packet_update( %{sender: "K5ABC"}, socket(), filter_fn: allow_all(), process_fn: record_process(self()) ) assert_received {:processed, packet} # Enrichment added nil device_* keys even for unknown identifier. assert Map.has_key?(packet, :device_model) end test "skips enrichment when enrich_packet: false" do {:noreply, _} = SharedPacketHandler.handle_packet_update( %{sender: "K5ABC"}, socket(), filter_fn: allow_all(), process_fn: record_process(self()), enrich_packet: false ) assert_received {:processed, packet} refute Map.has_key?(packet, :device_model) end end describe "packet_matches_callsign?/2" do test "matches on atom :sender key" do assert SharedPacketHandler.packet_matches_callsign?(%{sender: "K5ABC"}, "K5ABC") end test "matches on string 'sender' key" do assert SharedPacketHandler.packet_matches_callsign?(%{"sender" => "K5ABC"}, "K5ABC") end test "string key wins over atom key when both present" do # The implementation prefers the string key via Map.get fallback ordering. assert SharedPacketHandler.packet_matches_callsign?( %{"sender" => "K5ABC", sender: "OTHER"}, "K5ABC" ) end test "comparison is case-insensitive via Callsign.matches?" do assert SharedPacketHandler.packet_matches_callsign?(%{sender: "k5abc"}, "K5ABC") end test "returns false when mismatched" do refute SharedPacketHandler.packet_matches_callsign?(%{sender: "K5ABC"}, "W1XYZ") end end describe "has_weather_data?/1" do test "returns true when at least one weather field is present" do assert SharedPacketHandler.has_weather_data?(%{temperature: 72.0}) assert SharedPacketHandler.has_weather_data?(%{"humidity" => 50}) end test "returns false when no weather fields are present" do refute SharedPacketHandler.has_weather_data?(%{sender: "K5ABC"}) refute SharedPacketHandler.has_weather_data?(%{}) end end describe "enrich_with_device_info/1" do test "adds nil device_* keys when no device identifier" do result = SharedPacketHandler.enrich_with_device_info(%{sender: "K5ABC"}) assert result.device_model == nil assert result.device_vendor == nil assert result.device_contact == nil assert result.device_class == nil end test "still adds nil device_* when device_identifier is empty string" do result = SharedPacketHandler.enrich_with_device_info(%{device_identifier: ""}) assert result.device_model == nil end end describe "enrich_packets_with_device_info/1" do test "enriches each packet in the list" do packets = [ %{sender: "A", device_identifier: nil}, %{sender: "B", device_identifier: ""}, %{sender: "C", device_identifier: "APXYZ"} ] enriched = SharedPacketHandler.enrich_packets_with_device_info(packets) assert length(enriched) == 3 assert Enum.all?(enriched, &Map.has_key?(&1, :device_model)) end test "handles empty list" do assert SharedPacketHandler.enrich_packets_with_device_info([]) == [] end end describe "filter factories" do test "callsign_filter matches packets by sender" do f = SharedPacketHandler.callsign_filter("K5ABC") assert f.(%{sender: "K5ABC"}, :any) refute f.(%{sender: "W1XYZ"}, :any) end test "callsign_and_weather_filter requires both" do f = SharedPacketHandler.callsign_and_weather_filter("K5ABC") refute f.(%{sender: "K5ABC"}, :any) refute f.(%{sender: "OTHER", temperature: 72.0}, :any) assert f.(%{sender: "K5ABC", temperature: 72.0}, :any) end end end