mutare_gettext
A Mutareextension that teaches mutation testing to read
Gettext. It is an extension, not a mutator: it produces no mutations
of its own — it only makes Mutare's built-in mutators land correctly on a use Gettext module,
without poisoning the single metamutant build.
Install
# mix.exs
def deps do
[
{:mutare, "~> 0.1", only: [:dev, :test], runtime: false},
{:mutare_gettext, "~> 0.1", only: [:dev, :test], runtime: false}
]
end
# .mutare.exs
[extensions: [Mutare.Gettext]]
What it does
Gettext (>= 0.26) is two problems for a single-compile mutation tool:
use Gettext, backend: MyApp.Gettextregisters its backend by mutating the caller module, so Mutare's in-processuseexpansion raises and never surfaces theimport Gettext.Macrosit injects — the baregettext/ngettextcalls then never resolve.- A message id (
gettext("Hello")) must be a compile-time literal; splicing a mutation selector there makes the macro raise while expanding and poisons the build.
The extension fixes both via Mutare's two extension capability behaviours:
Mutare.UseExpansion(expand_use/3) takes over everyuse Gettextand injectsimport Gettext.Macros, so the bare calls resolve.Mutare.CallRouting(call_routes/0) routes each macro's arguments per position: the compile-time literals (message id, plural id, domain, context, backend) are:raw(never mutated → no poison), while the runtime arguments — thengettextpluralcountand the interpolationbindings— are:expression, so a stale plural threshold or wrong interpolation value still gets caught.
This is a whole-module :raw baseline plus a per-position override for every arity carrying a
count/bindings. The overrides are derived from the Gettext macro families (so a position
can't drift); the package's test cross-checks each one against the real Gettext.Macros.
Targets Gettext >= 0.26; on older versions it degrades to a harmless no-op.
Development
mix deps.get
mix test
mix check # format --check-formatted, credo, dialyzer
License
MIT — see LICENSE.