defmodule MicrowavepropWeb.Api.CoverageExtrasTest do @moduledoc """ Extra unit tests targeting defensive fall-through clauses that the routed integration tests don't exercise (Phoenix's params decoder always hands us strings, but the API controllers still ship `_, _` catch-alls so library-style direct invocation behaves predictably). """ use Microwaveprop.DataCase, async: true alias Microwaveprop.AccountsFixtures alias Microwaveprop.Radio.Contact alias MicrowavepropWeb.Api.Auth alias MicrowavepropWeb.Api.RateLimiter alias MicrowavepropWeb.Api.V1.ContactController alias MicrowavepropWeb.Api.V1.ContactJSON describe "Auth.require_auth/1 + .optional_auth/1 default args" do test "require_auth/1 with no opts halts unauthenticated requests" do conn = Auth.require_auth(Plug.Test.conn(:get, "/")) assert conn.status == 401 end test "optional_auth/1 with no opts passes anonymous requests through" do conn = Auth.optional_auth(Plug.Test.conn(:get, "/")) refute conn.halted end end describe "ContactJSON.maybe_notes branches" do test "anonymous-submitted contacts (user_id nil) hide notes from everyone" do contact = %Contact{user_id: nil, notes: "secret", band: nil} data = ContactJSON.show(%{contact: contact, viewer: AccountsFixtures.user_fixture()}).data assert data.notes == nil end test "non-owner viewers cannot read notes" do owner = AccountsFixtures.user_fixture() other = AccountsFixtures.user_fixture() contact = %Contact{user_id: owner.id, notes: "secret", band: nil} data = ContactJSON.show(%{contact: contact, viewer: other}).data assert data.notes == nil end test "owner sees the notes they wrote" do owner = AccountsFixtures.user_fixture() contact = %Contact{user_id: owner.id, notes: "private!", band: nil} data = ContactJSON.show(%{contact: contact, viewer: owner}).data assert data.notes == "private!" assert data.mine? == true end test "anonymous viewer with anonymous-submitted contact returns nil notes" do contact = %Contact{user_id: nil, notes: nil, band: nil} data = ContactJSON.show(%{contact: contact, viewer: nil}).data assert data.notes == nil assert data.mine? == false end end describe "RateLimiter ETS race recovery" do test "reset/0 + concurrent ensure_table do not crash" do RateLimiter.reset() # Force the ets table to exist and then immediately call call/2 with # a fresh conn — exercises the rescue clause on subsequent racing # creations under write_concurrency. tasks = for _ <- 1..8 do Task.async(fn -> RateLimiter.call(Plug.Test.conn(:get, "/"), anon_limit: 100) end) end results = Enum.map(tasks, &Task.await/1) assert Enum.all?(results, &(&1.status in [200, 429] or &1.status == nil)) end end describe "ContactController.parse_int catch-all" do test "parse_int falls back to the default when given an atom value" do # The route always encodes ints as binaries, so this clause is # invoked only for non-routed callers. Drive the action directly. conn = Phoenix.ConnTest.build_conn(:get, "/api/v1/contacts") conn = ContactController.index(conn, %{ "page" => :weird, "per_page" => :also_weird }) assert conn.status == 200 end end end