Adds focused tests across multiple modules to push toward the 87% threshold: - CoreComponents: pagination/1 (multi-page, ellipsis, params), list/1 (slot rendering), and signal_badge/1 across all RSSI bands. - ApiDocs/GraphQLDocs controllers: bypass-the-router pattern so the "scope-with-organization" branches are actually exercised (the public routes are unscoped, so the org branch is unreachable via get/2). - Mix.Tasks.Unused: text + JSON output, --only / --skip filters. - Mix.Tasks.JobCleanupTask: prod path with phoenix snmp enabled vs disabled (uses :job_cleanup_settle_ms = 0 to avoid the 1s sleep). - Member resolver: success path for remove/update_role on non-owner membership, and the changeset-error branch for an invalid role. - Check resolver: unauthenticated fallback clauses for list / get / create / update / delete. - RfLinks: nil-signal sort ordering, :unknown classification for nil/nil signal+snr, :degraded filter, capacity_utilization edge cases (max_rate 0/missing, both rates nil). - StatusHelpers: status_emoji + title_with_status across green / red branches (warning is unreachable given the active-alerts query). - ApiTokens: spawn_async_update/2 path with env != :test. - ImpactAnalysis: to_json/1 across nil and populated levels. - Maintenance: query helpers (default-arity wrappers, active range) and Show LiveView delete event redirecting to /maintenance. - Coverage map: probe_point event handler. - InvitationQuery: default-arity pending/1.
77 lines
2.6 KiB
Elixir
77 lines
2.6 KiB
Elixir
defmodule Mix.Tasks.UnusedTest do
|
|
# Mutates `Mix.shell/1` globally; cannot run concurrently with other tests
|
|
# that capture Mix shell output.
|
|
use ExUnit.Case, async: false
|
|
|
|
alias Mix.Tasks.Unused
|
|
|
|
setup do
|
|
previous_shell = Mix.shell()
|
|
Mix.shell(Mix.Shell.Process)
|
|
on_exit(fn -> Mix.shell(previous_shell) end)
|
|
:ok
|
|
end
|
|
|
|
describe "run/1" do
|
|
test "emits human-readable text output by default and returns :ok" do
|
|
assert :ok = Unused.run([])
|
|
|
|
# The task either reports "no unused" or a header — both go through
|
|
# `Mix.shell().info/1` which the Process shell captures as messages.
|
|
assert_received_info_matching(fn msg ->
|
|
msg =~ "unused public functions" or msg =~ "No unused public functions"
|
|
end)
|
|
end
|
|
|
|
test "honours --format json by emitting valid JSON" do
|
|
assert :ok = Unused.run(["--format", "json"])
|
|
json = collect_info_messages()
|
|
|
|
# The task always emits exactly one JSON document via Mix.shell().info/1.
|
|
decoded = Jason.decode!(json)
|
|
assert is_list(decoded)
|
|
|
|
for entry <- decoded do
|
|
assert is_binary(entry["module"])
|
|
assert is_binary(entry["function"])
|
|
assert is_integer(entry["arity"])
|
|
assert is_binary(entry["file"])
|
|
assert is_integer(entry["line"])
|
|
end
|
|
end
|
|
|
|
test "honours --only by filtering output to a module prefix" do
|
|
# No assertion on contents — just exercise the apply_only/2 branch.
|
|
assert :ok = Unused.run(["--only", "Towerops.NoSuchPrefix"])
|
|
|
|
assert_received_info_matching(fn msg ->
|
|
msg =~ "No unused public functions"
|
|
end)
|
|
end
|
|
|
|
test "honours --skip by removing modules under a prefix" do
|
|
# Just exercise the apply_skip branch — output depends on the build env.
|
|
assert :ok = Unused.run(["--skip", "Towerops"])
|
|
|
|
msg = collect_info_messages()
|
|
# Either we get the "found N" header or the "no unused" message.
|
|
assert msg =~ "unused public functions" or msg =~ "No unused public functions"
|
|
end
|
|
end
|
|
|
|
# ──────────────────────────────────────────────────────────────────────
|
|
# Helpers
|
|
|
|
defp collect_info_messages(acc \\ "") do
|
|
receive do
|
|
{:mix_shell, :info, [msg]} -> collect_info_messages(acc <> msg <> "\n")
|
|
after
|
|
0 -> String.trim(acc)
|
|
end
|
|
end
|
|
|
|
defp assert_received_info_matching(predicate) do
|
|
msg = collect_info_messages()
|
|
assert predicate.(msg), "no Mix shell info message matched the predicate. Got: #{inspect(msg)}"
|
|
end
|
|
end
|