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) refute decoded == [] for entry <- decoded do assert byte_size(entry["module"]) > 0 assert byte_size(entry["function"]) > 0 assert is_integer(entry["arity"]) assert byte_size(entry["file"]) > 0 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 =~ ~r/unused public functions|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