defmodule Mix.Tasks.Compile.UnusedTest do use ExUnit.Case, async: false alias Mix.Tasks.Compile.Unused alias MixUnused.Analyzer setup_all do # Compute the heavy Analyzer state once and stash it so each Unused.run/1 # call below skips re-scanning every BEAM file. {:ok, state: Analyzer.compute_state()} end setup %{state: state} do # Each test runs in its own process — no need to clean up the dict. Process.put(:mix_unused_extra_analyze_opts, precomputed_state: state) :ok end 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 test "exercises run/1 across all severity arg variants" do # Each Unused.run/1 call invokes the analyzer (which scans all BEAMs # and is the slow part). We exercise every severity branch in a # single test so we only pay analyze cost a small number of times. arg_lists = [ [], ["--severity", "error"], ["--severity", "warning"], ["--severity", "info"], ["--severity", "garbage"] ] assert Unused.manifests() == [] ExUnit.CaptureIO.capture_io(fn -> for args <- arg_lists do result = Unused.run(args) # credo:disable-for-next-line Jump.CredoChecks.ConditionalAssertion assert match?({:ok, _}, result) or match?({:error, _}, result) # compile result legitimately returns ok or error end end) end end end