defmodule Blogex.MutationConfigTest do # The mutation sensor is opt-in: a dependency and two aliases, deliberately # absent from `make verify`'s VERIFY_SENSORS. These pins keep the wiring # honest (dev/test only, never runtime) and keep the aliases reading the # scope files rather than duplicating a list in mix.exs. use ExUnit.Case test "muex is a dev/test-only, non-runtime dependency" do deps = Mix.Project.config()[:deps] assert {:muex, requirement, opts} = dep!(deps, :muex) assert requirement =~ "0.12" assert opts[:only] == [:dev, :test] assert opts[:runtime] == false end test "mutate and mutate.fast aliases are defined" do aliases = Mix.Project.config()[:aliases] assert is_function(aliases[:mutate], 1) assert is_function(aliases[:"mutate.fast"], 1) end test "mutation args always include the scope, the curated mutators and --fail-at 0" do args = Blogex.MixProject.mutation_args("mutation_scope_fast.txt", []) scope = Blogex.MixProject.read_mutation_scope("mutation_scope_fast.txt") assert "--fail-at" in args assert Enum.at(args, Enum.find_index(args, &(&1 == "--fail-at")) + 1) == "0" assert files_arg(args) == Enum.join(scope, ",") mutators = Enum.at(args, Enum.find_index(args, &(&1 == "--mutators")) + 1) assert mutators == "arithmetic,boolean,comparison,conditional,function_call,literal,return_value" end test "extra CLI args pass through so a single file can be targeted" do args = Blogex.MixProject.mutation_args("mutation_scope_fast.txt", ["--files", "lib/blogex/seo.ex"]) assert args |> Enum.chunk_every(2, 1, :discard) |> Enum.any?(fn ["--files", "lib/blogex/seo.ex"] -> true _ -> false end) end test "an empty scope fails loudly instead of running over nothing" do path = Path.join(System.tmp_dir!(), "muex-empty-scope-#{System.unique_integer([:positive])}.txt") File.write!(path, "\n \n") on_exit(fn -> File.rm(path) end) assert_raise Mix.Error, ~r/empty/, fn -> Blogex.MixProject.read_mutation_scope(path) end end defp dep!(deps, name) do case Enum.find(deps, fn {^name, _requirement} -> true {^name, _requirement, _opts} -> true _ -> false end) do {^name, requirement} -> {name, requirement, []} {^name, requirement, opts} -> {name, requirement, opts} nil -> flunk("expected #{inspect(name)} in deps/0") end end defp files_arg(args) do args |> Enum.chunk_every(2, 1, :discard) |> Enum.find_value(fn ["--files", files] -> files _ -> nil end) end end