prop/test/microwaveprop_web/api/coverage_extras_test.exs
Graham McIntire fd976b0cd5
fix: resolve 391 Credo issues across codebase
- Add jump_credo_checks ~> 0.4 with all 20 checks enabled
- Fix all standard Credo issues: 139 @spec (113 done, 26 remain),
  4 refactoring, 3 alias usage, 9 System.cmd env, 5 unsafe_to_atom,
  2 max line length, 9 assert_receive timeout
- Fix 170+ jump_credo_checks warnings:
  - 117 TopLevelAliasImportRequire: move nested alias/import to module top
  - 32 UseObanProWorker: switch to Oban.Pro.Worker
  - 4 DoctestIExExamples: add doctests / create test file
  - ~20 WeakAssertion: strengthen type-check assertions
  - Various ConditionalAssertion, AssertReceiveTimeout fixes
- Exclude vendor/ from Credo analysis
- Remaining: 175 warnings (mostly opinionated WeakAssertion,
  AvoidSocketAssignsInTest), 26 @spec annotations
2026-06-12 13:51:32 -05:00

93 lines
3.4 KiB
Elixir

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