From 4213fa3105f813db2bf634dde05186b7f62082f4 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Wed, 30 Jul 2025 14:09:43 -0500 Subject: [PATCH] test: Add comprehensive tests for non-position packets and edge cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added tests for packets with has_position: false (status, messages, telemetry) - Added callsign normalization to handle whitespace-only callsigns - Added tests for edge cases (whitespace, lowercase callsigns) - Improved robustness of callsign tracking feature 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- lib/aprsme/packets.ex | 16 ++- .../tracked_callsign_old_packet_test.exs | 114 ++++++++++++++++++ 2 files changed, 124 insertions(+), 6 deletions(-) diff --git a/lib/aprsme/packets.ex b/lib/aprsme/packets.ex index c8991e5..0b2a8d7 100644 --- a/lib/aprsme/packets.ex +++ b/lib/aprsme/packets.ex @@ -450,18 +450,22 @@ defmodule Aprsme.Packets do # Build base query with time filter # Only filter by position if not tracking a specific callsign + # Also normalize callsign to handle edge cases + callsign = opts[:callsign] + normalized_callsign = if is_binary(callsign), do: String.trim(callsign), else: "" + base_query = - if Map.has_key?(opts, :callsign) and opts[:callsign] != nil and opts[:callsign] != "" do - # When tracking a callsign, show all their packets regardless of position - from(p in Packet, - where: p.received_at >= ^time_ago - ) - else + if normalized_callsign == "" do # For general map view, only show packets with positions from(p in Packet, where: p.has_position == true, where: p.received_at >= ^time_ago ) + else + # When tracking a callsign, show all their packets regardless of position + from(p in Packet, + where: p.received_at >= ^time_ago + ) end # Apply spatial and other filters BEFORE limiting diff --git a/test/aprsme_web/live/map_live/tracked_callsign_old_packet_test.exs b/test/aprsme_web/live/map_live/tracked_callsign_old_packet_test.exs index 811d517..014101d 100644 --- a/test/aprsme_web/live/map_live/tracked_callsign_old_packet_test.exs +++ b/test/aprsme_web/live/map_live/tracked_callsign_old_packet_test.exs @@ -122,5 +122,119 @@ defmodule AprsmeWeb.MapLive.TrackedCallsignOldPacketTest do assert socket.assigns.tracked_callsign == "NOPACKETS-1" assert socket.assigns.tracked_latest_packet == nil end + + test "displays non-position packet for tracked callsign", %{conn: conn} do + # Create a status packet without position data - this is the key test case + non_position_packet = + packet_fixture(%{ + sender: "TEST-STATUS", + raw_packet: "TEST-STATUS>APRS:>Status message without position", + received_at: DateTime.utc_now(), + has_position: false, + lat: nil, + lon: nil, + data_type: "status" + }) + + # Navigate to the tracked callsign URL + {:ok, view, _html} = live(conn, "/TEST-STATUS") + + # Wait for map to be ready + send(view.pid, %{ + event: "map_ready", + data: %{ + center: %{lat: 35.0, lng: -97.0}, + zoom: 10, + bounds: %{ + north: 36.0, + south: 34.0, + east: -96.0, + west: -98.0 + } + } + }) + + :timer.sleep(100) + + # Check that the tracked callsign is set + assert render(view) =~ "TEST-STATUS" + + # The non-position packet should still be loaded + state = :sys.get_state(view.pid) + socket = elem(state, 1).socket + + assert socket.assigns.tracked_callsign == "TEST-STATUS" + assert socket.assigns.tracked_callsign_latest_packet.id == non_position_packet.id + assert socket.assigns.tracked_callsign_latest_packet.has_position == false + end + + test "displays message packet without position for tracked callsign", %{conn: conn} do + # Create a message packet without position data + message_packet = + packet_fixture(%{ + sender: "TEST-MSG", + raw_packet: "TEST-MSG>APRS::W5ISP :Hello there! This is a test message{001", + # 1 hour old + received_at: DateTime.add(DateTime.utc_now(), -3600, :second), + has_position: false, + lat: nil, + lon: nil, + data_type: "message", + aprs_messaging: true + }) + + # Navigate to the tracked callsign URL + {:ok, view, _html} = live(conn, "/TEST-MSG") + + # The message packet should be tracked despite no position + state = :sys.get_state(view.pid) + socket = elem(state, 1).socket + + assert socket.assigns.tracked_callsign == "TEST-MSG" + assert socket.assigns.tracked_callsign_latest_packet.id == message_packet.id + assert socket.assigns.tracked_callsign_latest_packet.aprs_messaging == true + end + + test "handles whitespace in callsign parameter", %{conn: conn} do + # Create a packet for testing + packet = + packet_fixture(%{ + sender: "TEST-WS", + raw_packet: "TEST-WS>APRS:>Test whitespace handling", + has_position: false + }) + + # Navigate with extra whitespace + {:ok, view, _html} = live(conn, "/ TEST-WS ") + + # Should normalize to uppercase and trim whitespace + state = :sys.get_state(view.pid) + socket = elem(state, 1).socket + + # The callsign should be normalized (trimmed and uppercased) + assert socket.assigns.tracked_callsign == "TEST-WS" + assert socket.assigns.tracked_callsign_latest_packet.id == packet.id + end + + test "handles lowercase callsign with non-position packet", %{conn: conn} do + # Create a telemetry packet without position + telemetry_packet = + packet_fixture(%{ + sender: "TEST-TELEM", + raw_packet: "TEST-TELEM>APRS:T#123,456,789,012,345,678,00000000", + has_position: false, + data_type: "telemetry" + }) + + # Navigate with lowercase callsign + {:ok, view, _html} = live(conn, "/test-telem") + + state = :sys.get_state(view.pid) + socket = elem(state, 1).socket + + # Should normalize to uppercase + assert socket.assigns.tracked_callsign == "TEST-TELEM" + assert socket.assigns.tracked_callsign_latest_packet.id == telemetry_packet.id + end end end