refactor: pattern-match InfoLive.Show path parsing + add tests
- parse_path_element_with_link splits its fat `if`/or-chain into three focused helpers: linkable_callsign?/1 (regex + alias check), path_alias?/1 (four String.starts_with guards), and classify_path_element/2 (link vs. text dispatched on the boolean). - display_for_element/2 chooses the callsign form with/without the asterisk via two function heads instead of an inline `if`. Adds 7 tests covering the parse_path_with_links/1 public API — plain callsigns, heard-via asterisk preservation, non-linkable aliases (WIDE/TRACE/RELAY/TCPIP), q-constructs, whitespace trimming, and mixed paths.
This commit is contained in:
parent
bcbaddc18b
commit
1d68868d27
2 changed files with 70 additions and 16 deletions
|
|
@ -599,24 +599,35 @@ defmodule AprsmeWeb.InfoLive.Show do
|
|||
|
||||
defp parse_path_element_with_link(element) do
|
||||
element = String.trim(element)
|
||||
|
||||
# Check if it's a callsign (with or without SSID)
|
||||
if Regex.match?(~r/^[A-Z0-9]{1,6}(-\d{1,2})?(\*)?$/, element) and
|
||||
not String.starts_with?(element, "WIDE") and
|
||||
not String.starts_with?(element, "TRACE") and
|
||||
not String.starts_with?(element, "RELAY") and
|
||||
not String.starts_with?(element, "TCPIP") and
|
||||
not String.starts_with?(element, "q") do
|
||||
# Remove asterisk if present (indicates the packet was digipeated through this station)
|
||||
callsign = String.replace(element, "*", "")
|
||||
display = if String.ends_with?(element, "*"), do: "#{callsign}*", else: callsign
|
||||
{:link, callsign, display}
|
||||
else
|
||||
# Not a linkable callsign, just return as text
|
||||
{:text, element, element}
|
||||
end
|
||||
classify_path_element(linkable_callsign?(element), element)
|
||||
end
|
||||
|
||||
# Only real callsigns (not digipeater aliases or q-constructs) become links.
|
||||
defp linkable_callsign?(element) do
|
||||
Regex.match?(~r/^[A-Z0-9]{1,6}(-\d{1,2})?(\*)?$/, element) and
|
||||
not path_alias?(element)
|
||||
end
|
||||
|
||||
defp path_alias?(element) do
|
||||
String.starts_with?(element, "WIDE") or
|
||||
String.starts_with?(element, "TRACE") or
|
||||
String.starts_with?(element, "RELAY") or
|
||||
String.starts_with?(element, "TCPIP") or
|
||||
String.starts_with?(element, "q")
|
||||
end
|
||||
|
||||
# Strip the trailing `*` from the canonical callsign while preserving it
|
||||
# in the display string so the UI still shows "was-heard-via" markers.
|
||||
defp classify_path_element(true, element) do
|
||||
callsign = String.replace(element, "*", "")
|
||||
{:link, callsign, display_for_element(String.ends_with?(element, "*"), callsign)}
|
||||
end
|
||||
|
||||
defp classify_path_element(false, element), do: {:text, element, element}
|
||||
|
||||
defp display_for_element(true, callsign), do: "#{callsign}*"
|
||||
defp display_for_element(false, callsign), do: callsign
|
||||
|
||||
defp decode_path_element(element) do
|
||||
element = String.trim(element)
|
||||
|
||||
|
|
|
|||
|
|
@ -99,4 +99,47 @@ defmodule AprsmeWeb.InfoLive.ShowHelpersTest do
|
|||
assert d > 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "parse_path_with_links/1" do
|
||||
test "returns empty list for non-binary input" do
|
||||
assert Show.parse_path_with_links(nil) == []
|
||||
assert Show.parse_path_with_links("") == []
|
||||
assert Show.parse_path_with_links(123) == []
|
||||
end
|
||||
|
||||
test "splits on commas and links plain callsigns" do
|
||||
result = Show.parse_path_with_links("K5ABC-1,W1XYZ")
|
||||
assert [{:link, "K5ABC-1", "K5ABC-1"}, {:link, "W1XYZ", "W1XYZ"}] = result
|
||||
end
|
||||
|
||||
test "preserves the heard-via asterisk in the display text" do
|
||||
assert [{:link, "K5ABC", "K5ABC*"}] = Show.parse_path_with_links("K5ABC*")
|
||||
end
|
||||
|
||||
test "does not link WIDE/TRACE/RELAY/TCPIP path aliases" do
|
||||
assert [{:text, "WIDE1-1", "WIDE1-1"}] = Show.parse_path_with_links("WIDE1-1")
|
||||
assert [{:text, "TRACE3-3", "TRACE3-3"}] = Show.parse_path_with_links("TRACE3-3")
|
||||
assert [{:text, "RELAY", "RELAY"}] = Show.parse_path_with_links("RELAY")
|
||||
assert [{:text, "TCPIP*", "TCPIP*"}] = Show.parse_path_with_links("TCPIP*")
|
||||
end
|
||||
|
||||
test "does not link q-constructs" do
|
||||
assert [{:text, "qAC", "qAC"}] = Show.parse_path_with_links("qAC")
|
||||
assert [{:text, "qAR", "qAR"}] = Show.parse_path_with_links("qAR")
|
||||
end
|
||||
|
||||
test "trims whitespace before linking" do
|
||||
assert [{:link, "K5ABC", "K5ABC"}] = Show.parse_path_with_links(" K5ABC ")
|
||||
end
|
||||
|
||||
test "mixes links and text in a single path" do
|
||||
result = Show.parse_path_with_links("K5ABC*,WIDE1-1,W1XYZ")
|
||||
|
||||
assert [
|
||||
{:link, "K5ABC", "K5ABC*"},
|
||||
{:text, "WIDE1-1", "WIDE1-1"},
|
||||
{:link, "W1XYZ", "W1XYZ"}
|
||||
] = result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue