diff --git a/lib/aprsme/callsign.ex b/lib/aprsme/callsign.ex index e49cc27..cb5b2a3 100644 --- a/lib/aprsme/callsign.ex +++ b/lib/aprsme/callsign.ex @@ -40,12 +40,8 @@ defmodule Aprsme.Callsign do def valid?(callsign) when is_binary(callsign) do trimmed = String.trim(callsign) - cond do - trimmed == "" -> false - byte_size(trimmed) < 3 -> false - byte_size(trimmed) > 15 -> false - true -> Regex.match?(~r/^[A-Z0-9]+(-[A-Z0-9]{1,2})?$/i, trimmed) - end + # Accept any non-empty callsign + trimmed != "" end def valid?(_), do: false @@ -74,10 +70,13 @@ defmodule Aprsme.Callsign do def extract_base(nil), do: "" def extract_base(callsign) when is_binary(callsign) do + # Split on last hyphen to get base callsign case String.split(callsign, "-") do - [base, _ssid] -> base - [base] -> base - _ -> "" + parts when length(parts) > 1 -> + parts |> Enum.drop(-1) |> Enum.join("-") + + _ -> + callsign end end @@ -98,9 +97,9 @@ defmodule Aprsme.Callsign do def extract_ssid(nil), do: "0" def extract_ssid(callsign) when is_binary(callsign) do + # Extract whatever comes after the last hyphen as SSID case String.split(callsign, "-") do - [_base, ssid] -> ssid - [_base] -> "0" + parts when length(parts) > 1 -> List.last(parts) _ -> "0" end end @@ -122,10 +121,15 @@ defmodule Aprsme.Callsign do def extract_parts(nil), do: {"", "0"} def extract_parts(callsign) when is_binary(callsign) do + # Split on last hyphen to separate base and SSID case String.split(callsign, "-") do - [base, ssid] -> {base, ssid} - [base] -> {base, "0"} - _ -> {"", "0"} + parts when length(parts) > 1 -> + ssid = List.last(parts) + base = parts |> Enum.drop(-1) |> Enum.join("-") + {base, ssid} + + _ -> + {callsign, "0"} end end diff --git a/test/aprsme/callsign_test.exs b/test/aprsme/callsign_test.exs new file mode 100644 index 0000000..98fc377 --- /dev/null +++ b/test/aprsme/callsign_test.exs @@ -0,0 +1,58 @@ +defmodule Aprsme.CallsignTest do + use ExUnit.Case, async: true + + alias Aprsme.Callsign + + describe "valid?/1" do + test "validates standard callsigns" do + assert Callsign.valid?("K5ABC") + assert Callsign.valid?("W1XYZ") + assert Callsign.valid?("N0CALL") + end + + test "validates callsigns with SSID" do + assert Callsign.valid?("K5ABC-1") + assert Callsign.valid?("W1XYZ-15") + assert Callsign.valid?("N0CALL-9") + end + + test "validates callsigns with hyphens in base callsign like VE-KTKI" do + assert Callsign.valid?("VE-KTKI") + assert Callsign.valid?("VE-KTKI-1") + assert Callsign.valid?("VE-TEST") + end + + test "rejects only empty callsigns" do + refute Callsign.valid?("") + refute Callsign.valid?(" ") + + # Now accepts any non-empty string + assert Callsign.valid?("123") + assert Callsign.valid?("-ABC") + assert Callsign.valid?("ABC-") + assert Callsign.valid?("ABC-123") + assert Callsign.valid?("ABC--1") + end + + test "handles nil input" do + refute Callsign.valid?(nil) + end + end + + describe "normalize/1" do + test "converts to uppercase and trims whitespace" do + assert Callsign.normalize("k5abc") == "K5ABC" + assert Callsign.normalize(" W1XYZ ") == "W1XYZ" + assert Callsign.normalize(" n0call-9 ") == "N0CALL-9" + end + + test "normalizes callsigns with hyphens in base" do + assert Callsign.normalize("ve-ktki") == "VE-KTKI" + assert Callsign.normalize(" VE-KTKI-1 ") == "VE-KTKI-1" + end + + test "handles nil input" do + assert Callsign.normalize(nil) == "" + end + end +end