aprs.me/test/aprsme/packet_field_whitelist_test.exs
Graham McIntire 403300f696
test: broaden unit & property-test coverage (61.8% → 64.7%)
Adds ~800 new tests (incl. 27 StreamData properties) across 22 modules
that previously had little or no coverage. Highlights:

- Pure utility modules (LogSanitizer, PacketFieldWhitelist,
  PacketSanitizer, DeviceParser, CoordinateUtils, BoundsUtils,
  ParamUtils, Convert, WeatherUnits) get thorough unit + property
  coverage including UTF-8 truncation boundaries, antimeridian
  longitude wrap, Haversine symmetry, and unit-conversion inverses.
- JSON view modules (CallsignJSON, ErrorJSON, ChangesetJSON) verified
  for envelope shape and error templating.
- Plugs (HealthCheck, RateLimiter, ApiCSRF) exercised for happy-path
  and halt paths.
- GenServer modules (RegexCache, CleanupScheduler, DeploymentNotifier)
  tested without touching the supervised singleton where possible.
- Drops the orphaned map_live/map_helpers_test.exs whose module name
  collided with the new live/shared/coordinate_utils_test.exs.
2026-04-23 13:32:09 -05:00

130 lines
4.3 KiB
Elixir

defmodule Aprsme.PacketFieldWhitelistTest do
use ExUnit.Case, async: true
use ExUnitProperties
alias Aprsme.PacketFieldWhitelist
describe "allowed_fields/0" do
test "returns a list of strings" do
fields = PacketFieldWhitelist.allowed_fields()
assert is_list(fields)
assert match?([_ | _], fields)
assert Enum.all?(fields, &is_binary/1)
end
test "contains core schema fields" do
fields = PacketFieldWhitelist.allowed_fields()
assert "sender" in fields
assert "base_callsign" in fields
assert "lat" in fields
assert "lon" in fields
assert "received_at" in fields
assert "raw_packet" in fields
end
end
describe "allowed?/1" do
test "accepts atoms that match allowed fields" do
assert PacketFieldWhitelist.allowed?(:sender)
assert PacketFieldWhitelist.allowed?(:raw_packet)
assert PacketFieldWhitelist.allowed?(:lat)
end
test "accepts strings that match allowed fields" do
assert PacketFieldWhitelist.allowed?("sender")
assert PacketFieldWhitelist.allowed?("raw_packet")
end
test "rejects unknown atoms" do
refute PacketFieldWhitelist.allowed?(:totally_bogus)
refute PacketFieldWhitelist.allowed?(:__struct__)
end
test "rejects unknown strings" do
refute PacketFieldWhitelist.allowed?("id")
refute PacketFieldWhitelist.allowed?("")
end
test "rejects non-atom, non-binary input" do
refute PacketFieldWhitelist.allowed?(123)
refute PacketFieldWhitelist.allowed?(nil)
refute PacketFieldWhitelist.allowed?(%{})
refute PacketFieldWhitelist.allowed?([])
end
end
describe "filter_fields/1" do
test "keeps allowed atom keys" do
input = %{sender: "K5ABC", lat: 30.0, bogus: "x"}
result = PacketFieldWhitelist.filter_fields(input)
assert result[:sender] == "K5ABC"
assert result[:lat] == 30.0
refute Map.has_key?(result, :bogus)
end
test "keeps allowed string keys" do
input = %{"sender" => "K5ABC", "unknown" => "x"}
result = PacketFieldWhitelist.filter_fields(input)
assert result["sender"] == "K5ABC"
refute Map.has_key?(result, "unknown")
end
test "preserves whichever key type caller used" do
atom_in = %{sender: "a"}
string_in = %{"sender" => "b"}
assert PacketFieldWhitelist.filter_fields(atom_in) == %{sender: "a"}
assert PacketFieldWhitelist.filter_fields(string_in) == %{"sender" => "b"}
end
test "returns empty map when no keys are allowed" do
assert PacketFieldWhitelist.filter_fields(%{bogus: 1, junk: 2}) == %{}
end
test "returns empty map on empty input" do
assert PacketFieldWhitelist.filter_fields(%{}) == %{}
end
end
describe "invalid_fields/1" do
test "returns only the disallowed keys as strings" do
input = %{"junk" => 2, sender: "x", bogus: 1}
assert PacketFieldWhitelist.invalid_fields(input) == ["bogus", "junk"]
end
test "returns empty list when every key is allowed" do
assert PacketFieldWhitelist.invalid_fields(%{sender: "x", lat: 1.0}) == []
end
test "returns sorted, deduplicated-looking output" do
input = %{z_bogus: 1, a_bogus: 2}
result = PacketFieldWhitelist.invalid_fields(input)
assert result == Enum.sort(result)
end
end
describe "property: filter_fields/1 is idempotent" do
property "running filter twice equals running once" do
check all(map <- map_of(atom(:alphanumeric), term())) do
once = PacketFieldWhitelist.filter_fields(map)
twice = PacketFieldWhitelist.filter_fields(once)
assert once == twice
end
end
property "every key in the output satisfies allowed?/1" do
check all(map <- map_of(atom(:alphanumeric), term())) do
result = PacketFieldWhitelist.filter_fields(map)
assert Enum.all?(Map.keys(result), &PacketFieldWhitelist.allowed?/1)
end
end
property "invalid_fields and filter_fields partition the input" do
check all(map <- map_of(atom(:alphanumeric), term())) do
kept = map |> PacketFieldWhitelist.filter_fields() |> Map.keys() |> Enum.map(&to_string/1)
dropped = PacketFieldWhitelist.invalid_fields(map)
all_keys = map |> Map.keys() |> Enum.map(&to_string/1)
assert Enum.sort(kept ++ dropped) == Enum.sort(all_keys)
end
end
end
end