prop/test/microwaveprop/propagation/band_weights_test.exs
Graham McIntire cb8445f329
fix: resolve 158/183 credo --strict warnings
- Add 17 missing @spec annotations (layouts, error_json, error_html, skewt_svg)
- Move 12+ nested alias/import/require to module top level
- Add phx-change/id attributes to 11 raw HTML <form> tags
- Remove 4 unused LiveView assigns (:bounds, :data_provider)
- Add 3 missing doctest references (HrrrNativeClient, BulkFetch, Accounts)
- Break 2 long lines (path_compute.ex:382)
- Strengthen weak test assertions (is_binary→byte_size, is_list→!=[])
- Replace Module.concat with Module.safe_concat (2 occurrences)
- Replace length/1 > 0 with list != [] (9 occurrences)
- Remove no-op assert true, fix no-assertion tests

Remaining: 24 socket.assigns introspection warnings (deliberate test
pattern for observable behavior testing), 1 formatter-resistant long
line, 3 app-code usage warnings.
2026-06-12 15:47:15 -05:00

163 lines
4.9 KiB
Elixir

defmodule Microwaveprop.Propagation.BandWeightsTest do
# async: false because BandWeights caches in :persistent_term, which is
# global to the BEAM. Each test resets the cache in setup so ordering
# is irrelevant, but concurrent runs would still see each other.
use ExUnit.Case, async: false
alias Microwaveprop.Propagation.BandWeights
@valid_json """
{
"generated_at": "2026-05-24T18:53:32+00:00",
"schema_version": 1,
"global_weights": {
"humidity": 0.1262, "time_of_day": 0.038, "td_depression": 0.101,
"refractivity": 0.0986, "sky": 0.0841, "season": 0.1134,
"wind": 0.0841, "rain": 0.1431, "pwat": 0.1147, "pressure": 0.0967
},
"band_overrides": {
"10000": {
"weights": {
"humidity": 0.20, "time_of_day": 0.04, "td_depression": 0.10,
"refractivity": 0.10, "sky": 0.08, "season": 0.11,
"wind": 0.08, "rain": 0.14, "pwat": 0.11, "pressure": 0.04
},
"n_samples": 54161,
"source": "contacts"
},
"144": {
"weights": {
"humidity": 0.18, "time_of_day": 0.02, "td_depression": 0.15,
"refractivity": 0.11, "sky": 0.06, "season": 0.12,
"wind": 0.06, "rain": 0.01, "pwat": 0.17, "pressure": 0.12
},
"n_samples": 12927,
"source": "pskr"
}
}
}
"""
setup do
# Cache is global to the BEAM; reset before every test to avoid
# bleed between cases.
BandWeights.reset()
prior_env = Application.get_env(:microwaveprop, :band_weights_json)
on_exit(fn ->
BandWeights.reset()
if prior_env do
Application.put_env(:microwaveprop, :band_weights_json, prior_env)
else
Application.delete_env(:microwaveprop, :band_weights_json)
end
end)
:ok
end
describe "lookup/1 with a valid JSON file" do
setup do
path = Path.join(System.tmp_dir!(), "band_weights_#{System.unique_integer([:positive])}.json")
File.write!(path, @valid_json)
Application.put_env(:microwaveprop, :band_weights_json, path)
on_exit(fn -> File.rm(path) end)
%{path: path}
end
test "returns the override weights for a band present in the file" do
result = BandWeights.lookup(10_000)
assert result.humidity == 0.20
assert result.pressure == 0.04
# All 10 keys present.
expected_keys =
MapSet.new([
:humidity,
:time_of_day,
:td_depression,
:refractivity,
:sky,
:season,
:wind,
:rain,
:pwat,
:pressure
])
assert MapSet.new(Map.keys(result)) == expected_keys
end
test "returns the override weights for a second band" do
result = BandWeights.lookup(144)
assert result.humidity == 0.18
end
test "returns nil for a band not present in the file" do
assert BandWeights.lookup(75_000) == nil
end
test "is cheap on repeat calls (cached)" do
first = BandWeights.lookup(10_000)
# Delete the source file — second call must still succeed from cache.
File.rm!(Application.fetch_env!(:microwaveprop, :band_weights_json))
second = BandWeights.lookup(10_000)
assert first == second
end
end
describe "lookup/1 when the file is missing" do
setup do
Application.put_env(:microwaveprop, :band_weights_json, "/nonexistent/path/band_weights.json")
:ok
end
test "returns nil for every band (does not raise)" do
assert BandWeights.lookup(10_000) == nil
assert BandWeights.lookup(50) == nil
end
end
describe "lookup/1 when the loader is disabled in config" do
setup do
Application.put_env(:microwaveprop, :band_weights_json, false)
:ok
end
test "returns nil for every band" do
assert BandWeights.lookup(10_000) == nil
assert BandWeights.lookup(144) == nil
end
end
describe "lookup/1 with malformed JSON" do
setup do
path = Path.join(System.tmp_dir!(), "band_weights_bad_#{System.unique_integer([:positive])}.json")
File.write!(path, "{ not valid json")
Application.put_env(:microwaveprop, :band_weights_json, path)
on_exit(fn -> File.rm(path) end)
%{path: path}
end
test "returns nil for every band (logs but does not raise)" do
assert BandWeights.lookup(10_000) == nil
end
end
describe "all_overrides/0" do
setup do
path = Path.join(System.tmp_dir!(), "band_weights_#{System.unique_integer([:positive])}.json")
File.write!(path, @valid_json)
Application.put_env(:microwaveprop, :band_weights_json, path)
on_exit(fn -> File.rm(path) end)
:ok
end
test "returns a map of all band overrides keyed by freq_mhz integer" do
result = BandWeights.all_overrides()
assert Map.has_key?(result, 10_000)
assert Map.has_key?(result, 144)
assert result[10_000].humidity == 0.20
end
end
end