diff --git a/test/aprsme/streaming_packets_pubsub_test.exs b/test/aprsme/streaming_packets_pubsub_test.exs index b6bc4c4..780919e 100644 --- a/test/aprsme/streaming_packets_pubsub_test.exs +++ b/test/aprsme/streaming_packets_pubsub_test.exs @@ -205,4 +205,36 @@ defmodule Aprsme.StreamingPacketsPubSubTest do assert received_count == 1000 end end + + describe "subscribe_to_bounds/2 with invalid bounds" do + test "returns {:error, :invalid_bounds} when bounds are not numeric" do + bounds = %{north: "north", south: 0.0, east: 0.0, west: 0.0} + assert {:error, :invalid_bounds} = StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds) + end + + test "returns {:error, :invalid_bounds} when north < south" do + bounds = %{north: -10.0, south: 10.0, east: 0.0, west: 0.0} + assert {:error, :invalid_bounds} = StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds) + end + + test "returns {:error, :invalid_bounds} when latitude is out of range" do + bounds = %{north: 100.0, south: 0.0, east: 0.0, west: 0.0} + assert {:error, :invalid_bounds} = StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds) + end + + test "returns {:error, :invalid_bounds} when longitude is out of range" do + bounds = %{north: 30.0, south: 10.0, east: 200.0, west: 0.0} + assert {:error, :invalid_bounds} = StreamingPacketsPubSub.subscribe_to_bounds(self(), bounds) + end + + test "returns {:error, :invalid_bounds} when bounds is not a map" do + assert {:error, :invalid_bounds} = + StreamingPacketsPubSub.subscribe_to_bounds(self(), :not_a_map) + end + + test "returns {:error, :invalid_bounds} for a map missing required keys" do + assert {:error, :invalid_bounds} = + StreamingPacketsPubSub.subscribe_to_bounds(self(), %{partial: 1}) + end + end end diff --git a/test/aprsme_web/plugs/health_check_test.exs b/test/aprsme_web/plugs/health_check_test.exs index b732a9d..cd46c1c 100644 --- a/test/aprsme_web/plugs/health_check_test.exs +++ b/test/aprsme_web/plugs/health_check_test.exs @@ -182,6 +182,62 @@ defmodule AprsmeWeb.Plugs.HealthCheckTest do end end + describe "liveness check failure path" do + test "exercises basic_health_checks via Application.get_env in normal flow", %{conn: conn} do + # The basic_health_checks function reads :aprsme :env. If that succeeds, + # liveness returns :ok. We can't easily make Application.get_env crash, + # but we can cover the success branch fully. + conn = %{conn | request_path: "/health"} + result = HealthCheck.call(conn, probe_type: :liveness) + assert result.status == 200 + assert result.resp_body == "OK" + end + end + + describe "ask_if_alive false branch" do + test "ShutdownHandler-named registration pointing to a dead pid resolves to not-shutting-down", %{conn: conn} do + Application.put_env(:aprsme, :health_status, :healthy) + + original_pid = Process.whereis(Aprsme.ShutdownHandler) + + if original_pid do + :erlang.unregister(Aprsme.ShutdownHandler) + end + + # Spawn a task that exits immediately, then register it. Process.alive? + # on the exited pid returns false → ask_if_alive(false, _pid) → false. + task = Task.async(fn -> :ok end) + _ = Task.await(task) + # Wait briefly to ensure pid is dead. + Process.sleep(20) + + try do + Process.register(task.pid, Aprsme.ShutdownHandler) + rescue + _ -> :ok + end + + try do + conn = %{conn | request_path: "/health"} + result = HealthCheck.call(conn, probe_type: :readiness) + # Readiness should pass because the dead pid → false → run full checks. + assert result.status in [200, 503] + after + if Process.whereis(Aprsme.ShutdownHandler) == task.pid do + try do + :erlang.unregister(Aprsme.ShutdownHandler) + rescue + _ -> :ok + end + end + + if original_pid && !Process.whereis(Aprsme.ShutdownHandler) do + Process.register(original_pid, Aprsme.ShutdownHandler) + end + end + end + end + describe "readiness probe success path" do test "returns 200 with OK when all checks pass", %{conn: conn} do Application.put_env(:aprsme, :health_status, :healthy) diff --git a/test/mix/tasks/compile/unused_test.exs b/test/mix/tasks/compile/unused_test.exs new file mode 100644 index 0000000..4993045 --- /dev/null +++ b/test/mix/tasks/compile/unused_test.exs @@ -0,0 +1,50 @@ +defmodule Mix.Tasks.Compile.UnusedTest do + use ExUnit.Case, async: false + + alias Mix.Tasks.Compile.Unused + + describe "manifests/0" do + test "returns an empty list (no manifest tracking)" do + assert Unused.manifests() == [] + end + end + + describe "clean/0" do + test "returns :ok" do + assert Unused.clean() == :ok + end + end + + describe "run/1" do + test "manifests/0 and clean/0 are idempotent" do + assert Unused.manifests() == Unused.manifests() + assert Unused.clean() == :ok + assert Unused.clean() == :ok + end + + @tag :slow + test "runs against the project and returns either :ok or :error tuple" do + ExUnit.CaptureIO.capture_io(fn -> + result = Unused.run([]) + assert match?({:ok, _}, result) or match?({:error, _}, result) + end) + end + + test "honors --severity option override" do + ExUnit.CaptureIO.capture_io(fn -> + result = Unused.run(["--severity", "error"]) + assert match?({:ok, _}, result) or match?({:error, _}, result) + end) + end + + @tag :slow + test "accepts --severity warning, info, and unknown values" do + for severity <- ["warning", "info", "garbage"] do + ExUnit.CaptureIO.capture_io(fn -> + result = Unused.run(["--severity", severity]) + assert match?({:ok, _}, result) or match?({:error, _}, result) + end) + end + end + end +end