aprs.me/test/aprsme/packets/clustering_test.exs
Graham McIntire b86153cd27
Fix all mix credo --strict warnings (188 → 0)
- 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
2026-06-12 16:27:20 -05:00

124 lines
4.6 KiB
Elixir

defmodule Aprsme.Packets.ClusteringTest do
use Aprsme.DataCase
alias Aprsme.Packet
alias Aprsme.Packets.Clustering
describe "cluster_packets/3" do
test "returns raw packets when zoom level is greater than 8" do
packets = [
%Packet{id: 1, lat: Decimal.new("40.7128"), lon: Decimal.new("-74.0060")},
%Packet{id: 2, lat: Decimal.new("40.7580"), lon: Decimal.new("-73.9855")}
]
result = Clustering.cluster_packets(packets, 9, %{})
assert result == {:raw_packets, packets}
end
test "handles packets with string keys" do
packets = [
%{"id" => "1", "lat" => 40.7128, "lon" => -74.0060},
%{"id" => "2", "lat" => "40.7580", "lon" => "-73.9855"}
]
result = Clustering.cluster_packets(packets, 7, %{})
assert {:heat_map, clusters} = result
assert clusters != []
end
test "returns clustered data when zoom level is 8 or less" do
packets = [
%Packet{id: 1, lat: Decimal.new("40.7128"), lon: Decimal.new("-74.0060")},
%Packet{id: 2, lat: Decimal.new("40.7580"), lon: Decimal.new("-73.9855")},
%Packet{id: 3, lat: Decimal.new("51.5074"), lon: Decimal.new("-0.1278")}
]
result = Clustering.cluster_packets(packets, 7, %{})
assert {:heat_map, clusters} = result
assert clusters != []
# Check cluster structure
[first_cluster | _] = clusters
assert Map.has_key?(first_cluster, :lat)
assert Map.has_key?(first_cluster, :lng)
assert Map.has_key?(first_cluster, :intensity)
end
test "groups nearby packets into single cluster with normalized intensity" do
# Two very close packets
packets = [
%Packet{id: 1, lat: Decimal.new("40.7128"), lon: Decimal.new("-74.0060")},
%Packet{id: 2, lat: Decimal.new("40.7130"), lon: Decimal.new("-74.0058")}
]
result = Clustering.cluster_packets(packets, 5, %{})
assert {:heat_map, clusters} = result
assert length(clusters) == 1
# Intensity is normalized: min(count / 50.0, 1.0) => min(2/50, 1.0) = 0.04
assert hd(clusters).intensity == 2 / 50.0
end
test "separates distant packets into different clusters" do
# Two far apart packets
packets = [
%Packet{id: 1, lat: Decimal.new("40.7128"), lon: Decimal.new("-74.0060")},
%Packet{id: 2, lat: Decimal.new("51.5074"), lon: Decimal.new("-0.1278")}
]
result = Clustering.cluster_packets(packets, 5, %{})
assert {:heat_map, clusters} = result
assert length(clusters) == 2
# Each cluster has 1 packet: min(1/50.0, 1.0) = 0.02
assert Enum.all?(clusters, &(&1.intensity == 1 / 50.0))
end
test "intensity is capped at 1.0 for large clusters" do
# 100 packets at the same location — intensity should cap at 1.0
packets =
for i <- 1..100 do
%Packet{id: i, lat: Decimal.new("40.7128"), lon: Decimal.new("-74.0060")}
end
result = Clustering.cluster_packets(packets, 5, %{})
assert {:heat_map, [cluster]} = result
assert cluster.intensity == 1.0
end
test "handles packets with nil coordinates" do
packets = [
%Packet{id: 1, lat: nil, lon: nil},
%Packet{id: 2, lat: Decimal.new("40.7128"), lon: Decimal.new("-74.0060")},
%Packet{id: 3, lat: Decimal.new("40.7130"), lon: nil}
]
result = Clustering.cluster_packets(packets, 5, %{})
assert {:heat_map, clusters} = result
# Only one valid packet should be clustered
assert length(clusters) == 1
end
test "cluster radius decreases with zoom level" do
# These points are ~0.014 degrees apart (about 1.5km)
packets = [
%Packet{id: 1, lat: Decimal.new("40.7128"), lon: Decimal.new("-74.0060")},
%Packet{id: 2, lat: Decimal.new("40.7228"), lon: Decimal.new("-74.0160")}
]
# At zoom 3, these should be one cluster (radius 1.25 degrees)
{:heat_map, zoom3_clusters} = Clustering.cluster_packets(packets, 3, %{})
assert length(zoom3_clusters) == 1
# At zoom 8, these should be two clusters (radius 0.039 degrees)
# but our points are only 0.014 degrees apart, so they'll still cluster
# Let's use points that are further apart
far_packets = [
%Packet{id: 1, lat: Decimal.new("40.7128"), lon: Decimal.new("-74.0060")},
%Packet{id: 2, lat: Decimal.new("40.8128"), lon: Decimal.new("-74.1060")}
]
# At zoom 7, these should be two clusters (0.1 degree apart > 0.078 radius)
{:heat_map, zoom7_clusters} = Clustering.cluster_packets(far_packets, 7, %{})
assert length(zoom7_clusters) == 2
end
end
end