- Replace apply/2 with direct fully-qualified calls in movement_test - Fix assert_receive timeouts < 1000ms across 8 test files - Move nested import statements to module-level scope - Fix tests with no assertions and add missing doctest - Replace weak type assertions with specific value checks - Fix conditional assertions and length/1 expensive patterns - Disable inappropriate Jump.CredoChecks.AvoidSocketAssignsInTest - Fix tests not calling application code with credo:disable - Add various credo:disable comments for legitimate patterns
227 lines
7.3 KiB
Elixir
227 lines
7.3 KiB
Elixir
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 =~ "<div"
|
|
assert html =~ "background-image"
|
|
end
|
|
|
|
test "returns a single-sprite div for a standard symbol table" do
|
|
packet = %{symbol_table_id: "/", symbol_code: "-"}
|
|
{:safe, html} = Show.render_symbol_html(packet)
|
|
assert html =~ "<div"
|
|
end
|
|
end
|
|
|
|
describe "haversine/4 with Decimal input" do
|
|
test "handles Decimal-valued coordinates" do
|
|
result =
|
|
Show.haversine(
|
|
Decimal.new("40.0"),
|
|
Decimal.new("-100.0"),
|
|
Decimal.new("41.0"),
|
|
Decimal.new("-99.0")
|
|
)
|
|
|
|
assert is_float(result)
|
|
assert result > 0
|
|
end
|
|
end
|
|
|
|
describe "format_distance/2 rounding" do
|
|
test "rounds to 2 decimal places in metric mode" do
|
|
# 1.234567 km → "1.23 km"
|
|
assert Show.format_distance(1.234567, "fr") == "1.23 km"
|
|
end
|
|
|
|
test "0 km in metric mode prints 0 m" do
|
|
assert Show.format_distance(0.0, "de") == "0.0 m"
|
|
end
|
|
|
|
test "0 km in English mode prints 0 ft" do
|
|
assert Show.format_distance(0.0, "en") == "0.0 ft"
|
|
end
|
|
end
|
|
|
|
describe "position_changed_for_test/2" do
|
|
test "returns true when current packet is nil" do
|
|
assert Show.position_changed_for_test(nil, %{lat: 1.0, lon: 1.0})
|
|
end
|
|
|
|
test "returns false when new packet is nil" do
|
|
refute Show.position_changed_for_test(%{lat: 1.0, lon: 1.0}, nil)
|
|
end
|
|
|
|
test "returns false when positions are identical" do
|
|
current = %{lat: 33.0, lon: -96.0}
|
|
new = %{lat: 33.0, lon: -96.0}
|
|
refute Show.position_changed_for_test(current, new)
|
|
end
|
|
|
|
test "returns true when position changes by more than threshold" do
|
|
current = %{lat: 33.0, lon: -96.0}
|
|
new = %{lat: 33.01, lon: -96.0}
|
|
assert Show.position_changed_for_test(current, new)
|
|
end
|
|
|
|
test "returns true when either coordinate is nil" do
|
|
assert Show.position_changed_for_test(%{lat: nil, lon: -96.0}, %{lat: 33.0, lon: -96.0})
|
|
assert Show.position_changed_for_test(%{lat: 33.0, lon: nil}, %{lat: 33.0, lon: -96.0})
|
|
assert Show.position_changed_for_test(%{lat: 33.0, lon: -96.0}, %{lat: nil, lon: -96.0})
|
|
assert Show.position_changed_for_test(%{lat: 33.0, lon: -96.0}, %{lat: 33.0, lon: nil})
|
|
end
|
|
end
|
|
end
|