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 is_map(result) 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 is_map(result) assert Map.has_key?(result, 10_000) assert Map.has_key?(result, 144) assert result[10_000].humidity == 0.20 end end end