defmodule AprsmeWeb.InfoLive.ShowHelpersTest do use ExUnit.Case, async: true alias AprsmeWeb.InfoLive.Show describe "format_distance/2 with English locale (imperial)" do test "uses feet for distances under a mile" do # 0.5 km → ~0.31 miles → ~1641 ft result = Show.format_distance(0.5, "en") assert result =~ "ft" refute result =~ "mi" end test "uses miles for distances >= 1 mile" do # 10 km → ~6.21 miles result = Show.format_distance(10.0, "en") assert result =~ "mi" refute result =~ "ft" end test "default locale is English" do assert Show.format_distance(10.0) =~ "mi" end end describe "format_distance/2 with non-English locale (metric)" do test "uses meters for distances under 1 km" do result = Show.format_distance(0.5, "de") assert result =~ "m" refute result =~ "km" end test "uses km for longer distances" do result = Show.format_distance(5.0, "fr") assert result =~ "km" end test "handles multiple metric locales" do for loc <- ["es", "de", "fr", "ja"] do assert Show.format_distance(10.0, loc) =~ "km" end end end describe "calculate_course/4" do test "returns 0 (or 360) for due north" do # From (0,0) to (1,0) — moving north. bearing = Show.calculate_course(0.0, 0.0, 1.0, 0.0) # credo:disable-for-next-line Jump.CredoChecks.ConditionalAssertion assert bearing == 0.0 or bearing == 360.0 # calculate_course for due north legitimately returns 0.0 or 360.0 end test "returns ~90 for due east" do # From (0,0) to (0,1) — moving east. bearing = Show.calculate_course(0.0, 0.0, 0.0, 1.0) assert_in_delta bearing, 90.0, 0.5 end test "returns ~180 for due south" do bearing = Show.calculate_course(1.0, 0.0, 0.0, 0.0) assert_in_delta bearing, 180.0, 0.5 end test "returns ~270 for due west" do bearing = Show.calculate_course(0.0, 1.0, 0.0, 0.0) assert_in_delta bearing, 270.0, 0.5 end test "always returns a value in 0..360" do for {lat1, lon1, lat2, lon2} <- [ {0.0, 0.0, 45.0, 45.0}, {10.0, 20.0, -10.0, -20.0}, {0.0, 0.0, 0.0, -1.0} ] do b = Show.calculate_course(lat1, lon1, lat2, lon2) assert b >= 0 assert b <= 360 end end test "accepts Decimal inputs" do result = Show.calculate_course(Decimal.new("0.0"), Decimal.new("0.0"), Decimal.new("1.0"), Decimal.new("0.0")) assert is_float(result) end end describe "haversine/4" do test "returns 0 for identical points" do assert Show.haversine(40.0, -100.0, 40.0, -100.0) == 0.0 end test "is symmetric" do a = Show.haversine(40.0, -100.0, 41.0, -99.0) b = Show.haversine(41.0, -99.0, 40.0, -100.0) assert_in_delta a, b, 0.001 end test "returns positive distance for distinct points" do d = Show.haversine(40.0, -100.0, 41.0, -99.0) 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 describe "render_symbol_html/2" do test "returns an empty raw for a nil packet" do result = Show.render_symbol_html(nil) # raw("") — a safe-iodata pair. assert {:safe, ""} = result end test "returns an overlay div for a packet with a uppercase-letter overlay table_id" do packet = %{symbol_table_id: "A", symbol_code: ">"} {:safe, html} = Show.render_symbol_html(packet, 24) assert html =~ "